I am currently attempting to have a custom dialog on a fragment to bring text back to the fragment. I have the dialog setup but when I click on the button to bring up the dialog I get this error.
java.lang.ClassCastException: com.example.android.app.MainActivity#4c01a76must implement StatusDialogListener
I then found this stack post talking about the issue
From reading the error and the stack post it seems that the issue is that I have to implement the dialog class onto the activity that is connected to the fragment.
So I implemented the listener into my main activity
public class MainActivity extends AppCompatActivity implements ... Status_Dialog.StatusDialogListner
After implementing it, I got the error below:
Class 'MainActivity' must either be declared abstract or implement abstract method 'applyText(String)' in 'StatusDialogListner
Which I fixed by adding the code below to the Activity:
#Override
public void applyText(String status) {
}
This allows the app to run and display the dialog with no errors.
The issue is now my adapter will not get the text from the dialog so I believe it is to do with the fact that I also have an applyText in my fragment and main activity when I ran the debugger applytext in the fragment was never called. I am lost at this point
Code
Dialog
public class Status_Dialog extends AppCompatDialogFragment {
private EditText editTextStatus;
private StatusDialogListner listner;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.layout_status_dialog, null);
editTextStatus = view.findViewById(R.id.new_status);
builder.setView(view)
.setTitle("Change Status")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
String status = editTextStatus.getText().toString();
listner.applyText(status);
}
});
return builder.create();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listner = (StatusDialogListner) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement StatusDialogListener");
}
}
public interface StatusDialogListner {
void applyText(String status);
}
}
Fragment
public class profile_fragment extends Fragment implements Status_Dialog.StatusDialogListner {
private static final int GALLERY_PICK = 1;
private DatabaseReference mUserDatabase;
//Android Layout
private FirebaseUser mCurrentUser;
private CircleImageView mDisplayImage;
private TextView mName;
private TextView mStatus;
private Button mStatusBtn;
private Button mImageBtn;
private ProgressDialog mProgressDialog;
private StorageReference mImageStorage;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListner;
private static final String KEY_NAME = "name";
private static final String KEY_STATUS = "status";
private static final String KEY_IMAGE = "image";
private static final String TAG = "user_profile";
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile_fragment, container, false);
mDisplayImage = view.findViewById(R.id.profile_picture);
mName = view.findViewById(R.id.profile_user_name);
mStatus = view.findViewById(R.id.profile_user_status);
mStatusBtn = view.findViewById(R.id.profile_change_status_btn);
mImageBtn = view.findViewById(R.id.profile_change_image_btn);
mImageStorage = FirebaseStorage.getInstance().getReference();
mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
final String current_uid = mCurrentUser.getUid();
DocumentReference mUsersDB = db.collection("Users").document(current_uid);
// FirebaseUser currentFirebaseUser = FirebaseAuth.getInstance().getCurrentUser() ;
// Toast.makeText(this, "ttt" + currentFirebaseUser.getUid(), Toast.LENGTH_SHORT).show();
mStatusBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
openDialog();
/*
String status_value = mStatus.getText().toString();
Intent status_intent = new Intent(getActivity(), change_status.class);
status_intent.putExtra("status_value", status_value);
startActivity(status_intent);
*/
}
});
mImageBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(galleryIntent, "Select Image"), GALLERY_PICK);
/*
CropImage.activity()
.setGuidelines(CropImageView.Guidelines.ON)
.start(SettingsActivity.this);
*/
}
});
mUsersDB.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
String name = documentSnapshot.getString(KEY_NAME);
mName.setText(name);
String status = documentSnapshot.getString(KEY_STATUS);
mStatus.setText(status);
FirebaseUser currentFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();
} else {
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
return view;
}
public void openDialog(){
Status_Dialog status_dialog = new Status_Dialog();
status_dialog.show(getActivity().getSupportFragmentManager(), "TEST?");
}
#Override
public void applyText(String status) {
mStatus.setText(status);
}
...
Problem is here:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listner = (StatusDialogListner) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement StatusDialogListener");
}
}
Note that listner is set during the onAttach and it is receiving the instance of Context. In other words, it is receiving the instance of the host activity (That's why you had to implement the interface in the MainActivity)
I think you can update your code as follows:
1) Remove this from the dialog. This way, your activity no longer must implement StatusDialogListener
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listner = (StatusDialogListner) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "must implement StatusDialogListener");
}
}
2) Update this on Dialog:
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if(listner != null) { // ADD THIS NULL CHECK SINCE LISTNER MAY BE NULL
String status = editTextStatus.getText().toString();
listner.applyText(status);
}
}
});
3) Add this to the dialog:
public void setListener(StatusDialogListner newListener) {
this.listner = newListener;
}
4) Update this on the fragment:
public void openDialog(){
Status_Dialog status_dialog = new Status_Dialog();
status_dialog.setListener(this); // ADD THIS NEW LINE
status_dialog.show(getActivity().getSupportFragmentManager(), "TEST?");
}
5) Remove below code from MainActivity
// Remove the implementation of Status_Dialog.StatusDialogListner from MainActivity
// And remove the method below:
#Override
public void applyText(String status) {
}
Related
I'm trying to display from data from my Firebase database show in Firebase Recyclerview , This my Database
And i try use the same as tutorial code from
Firebase UI
I'm try and get this result
I'm fairly new to Android and programming in general, so any help would be appreciated. Here is the relevant code.
PostlistFragment
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = getActivity();
final Dialog mDialog = new Dialog(mActivity, R.style.NewDialog);
mDialog.addContentView(
new ProgressBar(mActivity),
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
);
mDialog.setCancelable(true);
mDialog.show();
// Set up Layout Manager, reverse layout
LinearLayoutManager mManager = new LinearLayoutManager(mActivity);
mManager.setReverseLayout(true);
mManager.setStackFromEnd(true);
mRecycler.setLayoutManager(mManager);
// Set up FirebaseRecyclerAdapter with the Query
Query postsQuery = getQuery(mDatabase);
mAdapter = new FirebaseRecyclerAdapter<PostMainboard, MainboardViewHolder>(PostMainboard.class, R.layout.mainboard_list, MainboardViewHolder.class, postsQuery) {
#Override
public void onDataChanged() {
super.onDataChanged();
mDialog.dismiss();
}
#Override
protected void populateViewHolder(final MainboardViewHolder viewHolder, final PostMainboard model, final int position) {
final DatabaseReference postRef = getRef(position);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mActivity, MainboardDetailActivity.class);
intent.putExtra(MainboardDetailActivity.EXTRA_POST_KEY, postRef.getKey());
startActivity(intent);
}
});
}
};
mRecycler.setAdapter(mAdapter);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null) {
mAdapter.cleanup();
}
}
public abstract Query getQuery(DatabaseReference databaseReference);
And result of my detail activity got same not show every one
Here My Detail Activity Code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_mainboard_detail);
mBodyView = (TextView)findViewById(R.id.post_detail);
mAuthorView = (TextView)findViewById(R.id.txt_author);
mTitleView = (TextView)findViewById(R.id.post_topic);
mDateView = (TextView)findViewById(R.id.post_date_time);
mCommentsRecycler = (RecyclerView) findViewById(R.id.recycler_comments);
mCommentsRecycler.setLayoutManager(new LinearLayoutManager(this));
mCommentField = (EditText) findViewById(R.id.comment_field);
Button mCommentButton = (Button) findViewById(R.id.button_post_comment);
mCommentButton.setOnClickListener(this);
// Get post key from intent
String mPostKey = getIntent().getStringExtra(EXTRA_POST_KEY);
if (mPostKey == null) {
throw new IllegalArgumentException("Must pass EXTRA_POST_KEY");
}
// Initialize Database
mPostReference = FirebaseDatabase.getInstance().getReference().child("mainboard").child(mPostKey);
mCommentsReference = FirebaseDatabase.getInstance().getReference().child("cm-mainboard").child(mPostKey);
}
#Override
public void onStart() {
super.onStart();
// Add value event listener to the post
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
PostMainboard post = dataSnapshot.getValue(PostMainboard.class);
User user = dataSnapshot.getValue(User.class);
mAuthorView.setText(user.uid);
mTitleView.setText(post.postTopic);
mBodyView.setText(post.postDetail);
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
Toast.makeText(MainboardDetailActivity.this, "Failed to load post.", Toast.LENGTH_SHORT).show();
}
};
mPostReference.addValueEventListener(postListener);
// Keep copy of post listener so we can remove it when app stops
mPostListener = postListener;
// Listen for comments
mAdapter = new CommentAdapter(this, mCommentsReference);
mCommentsRecycler.setAdapter(mAdapter);
}
#Override
public void onStop() {
super.onStop();
if (mPostListener != null) {
mPostReference.removeEventListener(mPostListener);
}
mAdapter.cleanupListener();
}
Post Class
public class PostMainboard{
public String uid;
public String auther;
public String postTopic;
public String postDetail;
public String postImageUrl;
public String postID;
private String postlatlon;
public long timeCreated;
public PostMainboard(){
}
public PostMainboard(String uid, String auther , String postTopic , String postDetail,long timeCreated)
{
this.uid = uid;
this.auther = auther;
this.postTopic = postTopic;
this.postDetail = postDetail;
this.postImageUrl = postImageUrl;
this.postID = postID;
this.timeCreated = timeCreated;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("mb_id", uid);
result.put("mb_auther" , auther);
result.put("mb_title", postTopic);
result.put("mb_body", postDetail);
result.put("mb_create", timeCreated);
return result;
}
User class
public class User {
public String uid;
public String user_fname;
private String user_lname;
private String user_idcard;
private String email;
private String user_phone;
public User(){
}
public User(String uid ,String user_fname, String user_lname, String user_idcard, String email, String user_phone) {
this.uid = uid;
this.user_fname = user_fname;
this.user_lname = user_lname;
this.user_idcard = user_idcard;
this.email = email;
this.user_phone = user_phone;
}
ViewHolder
public class MainboardViewHolder extends RecyclerView.ViewHolder {
private TextView authorView;
private TextView bodyView;
private TextView titleView;
private TextView dateView;
public MainboardViewHolder(View itemView) {
super(itemView);
authorView = (TextView)itemView.findViewById(R.id.txt_author);
bodyView = (TextView)itemView.findViewById(R.id.post_detail);
titleView = (TextView)itemView.findViewById(R.id.post_topic);
dateView = (TextView)itemView.findViewById(R.id.post_date_time);
}
public void bindToPost (PostMainboard postMainboard)
{
authorView.setText(postMainboard.auther);
bodyView.setText(postMainboard.postDetail);
titleView.setText(postMainboard.postTopic);
dateView.setText((int) postMainboard.timeCreated);
}
Mainboard fragment
public class MainboardFragment extends PostListFragment{
public MainboardFragment() {
// Required empty public constructor
}
#Override
public Query getQuery(DatabaseReference databaseReference) {
return databaseReference.child("mainboard").orderByKey();
}
It looks like you have forgotten to populate the ViewHolder (MainboardViewHolder).
In "PostlistFragment" under "populateViewHolder" you need to call viewHolder.bindToPost(model) to bind the data to your textviews and so forth.
Try this:
#Override
protected void populateViewHolder(final MainboardViewHolder viewHolder, final PostMainboard model, final int position) {
final DatabaseReference postRef = getRef(position);
viewHolder.bindToPost(model);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mActivity, MainboardDetailActivity.class);
intent.putExtra(MainboardDetailActivity.EXTRA_POST_KEY, postRef.getKey());
startActivity(intent);
}
});
}
Also, your getQuery method is abstract and empty. It should probably look like this:
#Override
public Query getQuery(DatabaseReference databaseReference) {
return databaseReference.getReference("mainboard").orderByKey();
}
I'm saying "probably" because I can't see how you have initialized mDatabase. In the future, please paste complete code if you wan't better and faster answers.
I implemented LiveData in my project, but I'm a little bit confused about it. It works, but I don't know is it the proper way.
My live data class:
public class ClientLiveData extends LiveData<List<Client>> {
private Context context;
private BroadcastReceiver dataChangedReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Logger.logLiveData("Data changed");
loadData();
}
};
public ClientLiveData(Context context) {
this.context = context.getApplicationContext();
loadData();
}
#Override
protected void onActive() {
super.onActive();
Logger.logLiveData("Activate live data");
LocalBroadcastManager.getInstance(context).registerReceiver(dataChangedReciever, new IntentFilter(DpnPreferences.DATA_CHANGED_FILTER));
}
#Override
protected void onInactive() {
super.onInactive();
Logger.logLiveData("Inactivate live data");
LocalBroadcastManager.getInstance(context).unregisterReceiver(dataChangedReciever);
}
private void loadData() {
new AsyncTask<Void, Void, List<Client>>() {
#Override
protected List<Client> doInBackground(Void... params) {
Logger.logLiveData("Loading data");
IClientDao clientDao = new DaoFactory().getClientDao();
List<Client> clients = clientDao.getAllClients();
Logger.logLiveData("Loading clients "+clients.size());
return clients;
}
#Override
protected void onPostExecute(List<Client> clients) {
super.onPostExecute(clients);
Logger.logLiveData("Set value for ViewModel");
setValue(clients);
}
}.execute();
}
}
My ViewModel class
public class ClientViewModel extends AndroidViewModel {
private final ClientLiveData data;
public ClientViewModel(Application application) {
super(application);
data = new ClientLiveData(application);
}
public LiveData<List<Client>> getData(){
return data;
}
}
I use it in my MainActivity like this:
clientViewModel = ViewModelProviders.of(this).get(ClientViewModel.class);
clientViewModel.getData().observe(this, new Observer<List<Client>>() {
#Override
public void onChanged(#Nullable List<Client> clients) {
Logger.logLiveData("Notify adapter dataset changed");
if (clientsAdapter != null) clientsAdapter.notifyDataSetChanged();
}
});
In my mock test case at first I delete all client from db, than I load a few clients from a raw json, save them into db.
After I can add new clients from an AlertDialog like this:
#OnClick (R.id.addClient_button)
public void onClick() {
final LinearLayout container = new LinearLayout(this);
container.setOrientation(LinearLayout.VERTICAL);
final EditText clientNameText = new EditText(this);
final EditText clientSpText = new EditText(this);
container.addView(clientNameText);
container.addView(clientSpText);
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle("Add new client")
.setView(container);
builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String clientName = clientNameText.getText().toString();
String clientSp = clientSpText.getText().toString();
Client client = new Client(clientName, clientSp, "", 1, "1. Rendelő", "www.obudamaganrendelo.hu");
client.save();
dialog.dismiss();
LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(new Intent(DATA_CHANGED_FILTER));
}
});
builder.show();
}
As I wrote it works fine, after I add a new client from AlertDialog the adapter updates.
But it would be nice if somebody confirms this implementation is a proper way of use ViewModel and LiveData.
Thanks
I'm trying to follow the Nest SDK on github and the sample code. My fragment code is as follows -
/**
* A placeholder fragment containing a simple view.
*/
public class ThermoActivityFragment extends Fragment implements View.OnClickListener {
private static final String TAG = ThermoActivity.class.getSimpleName(); // for log
// Nest API instance holder
private NestAPI tNest;
private NestToken tToken;
private Thermostat tThermo;
private Structure tStruct;
// Save the ID's and secret
private static final String CLIENT_ID = Constants.CLIENT_ID;
private static final String CLIENT_SECRET = Constants.CLIENT_SECRET;
private static final String REDIRECT_URL = Constants.REDIRECT_URL;
private static final int AUTH_TOKEN_REQUEST_CODE = 111;
private static final int RESULT_OK = -1;
private static final String THERMOSTAT_KEY = "thermostat_key";
private static final String STRUCTURE_KEY = "structure_key";
private static final String DEG_F = "%d°F";
// Text View
private TextView tTempIncr;
private TextView tTempDecr;
private TextView tSetTemp;
public ThermoActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_thermo, container, false);
tTempIncr = (TextView) view.findViewById(R.id.temp_incr);
tTempDecr = (TextView) view.findViewById(R.id.temp_decr);
tSetTemp = (TextView) view.findViewById(R.id.temp_value);
view.findViewById(R.id.temp_incr).setOnClickListener(this);
view.findViewById(R.id.temp_decr).setOnClickListener(this);
NestAPI.setAndroidContext(getContext());
tNest = NestAPI.getInstance();
tNest.setConfig(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);
// Auth flow
tToken = ThermoSettings.loadAuthToken(getContext());
if (tToken != null) {
authenticate(tToken);
} else {
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
if (savedInstanceState != null) {
tThermo = savedInstanceState.getParcelable(THERMOSTAT_KEY);
tStruct = savedInstanceState.getParcelable(STRUCTURE_KEY);
//updateViews();
}
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(THERMOSTAT_KEY, tThermo);
outState.putParcelable(STRUCTURE_KEY, tStruct);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode != RESULT_OK || requestCode != AUTH_TOKEN_REQUEST_CODE) {
Log.e(TAG, "Finished with no result.");
return;
}
tToken = NestAPI.getAccessTokenFromIntent(intent);
if (tToken != null) {
ThermoSettings.saveAuthToken(getContext(), tToken);
authenticate(tToken);
} else {
Log.e(TAG, "Unable to resolve access token from payload.");
}
}
#Override
public void onStop() {
Log.d(TAG, "onStop");
super.onStop();
tNest.removeAllListeners();
}
#Override
public void onClick(View v) {
if (tThermo == null || tStruct == null)
return;
String tThermoId = tThermo.getDeviceId();
long temp = tThermo.getTargetTemperatureF();
switch (v.getId()) {
case R.id.temp_incr:
System.out.println("Temp Incr");
++temp;
tSetTemp.setText(String.format(DEG_F, temp));
tNest.thermostats.setTargetTemperatureF(tThermoId, temp);
break;
case R.id.temp_decr:
--temp;
tSetTemp.setText(String.format(DEG_F, temp));
tNest.thermostats.setTargetTemperatureF(tThermoId, temp);
break;
}
}
/**
* Authenticate with the Nest API and start listening for updates.
*
* #param token the token used to authenticate.
*/
private void authenticate(NestToken token) {
//NestAPI nest = NestAPI.getInstance();
tNest.authWithToken(token, new NestListener.AuthListener() {
#Override
public void onAuthSuccess() {
Log.v(TAG, "Authentication succeeded.");
fetchData();
}
#Override
public void onAuthFailure(NestException exception) {
Log.e(TAG, "Authentication failed with error: " + exception.getMessage());
ThermoSettings.saveAuthToken(getActivity(), null);
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
#Override
public void onAuthRevoked() {
Log.e(TAG, "Auth token was revoked!");
ThermoSettings.saveAuthToken(getActivity(), null);
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
});
}
/**
* Setup global listener, start listening, and update view when update received.
*/
private void fetchData() {
tNest.addGlobalListener(new NestListener.GlobalListener() {
#Override
public void onUpdate(#NonNull GlobalUpdate update) {
tThermo = update.getThermostats().get(0);
//System.out.println(tThermo);
tStruct = update.getStructures().get(0);
//updateViews();
}
});
}
}
The Settings file where I save the token is as follows -
public class ThermoSettings {
private static final String TOKEN_KEY = "token";
private static final String EXPIRATION_KEY = "expiration";
public static void saveAuthToken(Context context, NestToken token) {
if (token == null) {
getPrefs(context).edit().remove(TOKEN_KEY).remove(EXPIRATION_KEY).commit();
return;
}
getPrefs(context).edit()
.putString(TOKEN_KEY, token.getToken())
.putLong(EXPIRATION_KEY, token.getExpiresIn())
.commit();
}
public static NestToken loadAuthToken(Context context) {
final SharedPreferences prefs = getPrefs(context);
final String token = prefs.getString(TOKEN_KEY, null);
final long expirationDate = prefs.getLong(EXPIRATION_KEY, -1);
if (token == null || expirationDate == -1) {
return null;
}
return new NestToken(token, expirationDate);
}
private static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(NestToken.class.getSimpleName(), 0);
}
}
What I'm trying to do -
I'm using a button on the homepage to enter the Activity. When I press the button, I see the Nest Authorization webpage, When I click on Accept, I see my UI but don't see the 'Authentication Succeeded' message in the log.
Can someone tell me what I'm doing wrong?
I finally got it to work. Earlier I was trying to make it work from a fragment. After I deleted the fragment and moved the code to MainActivity, it started to work.
i had made an application. And i wanted to add an End User license agreement to my app. So i had created a class to do it...
firstly i used to show my EULA with the inbuilt AlertDialog of android.
it worked fine..
Then i had made my own custom AlertDialog, and then tried to show the ELUA on my custom dialog. Now it works fine... The files were like...
//my Eula.java file...
//Gets the Eula file from assests folder...
class Eula {
private static final String ASSET_EULA = "EULA";
private static final String PREFERENCE_EULA_ACCEPTED = "eula.accepted";
private static final String PREFERENCES_EULA = "eula";
static interface OnEulaAgreedTo {
void onEulaAgreedTo();
}
static boolean show(final Activity activity)
{
final SharedPreferences preferences = activity.getSharedPreferences(PREFERENCES_EULA,
Activity.MODE_PRIVATE);
if (!preferences.getBoolean(PREFERENCE_EULA_ACCEPTED, false))
{
final CustomDialog.Builder builder = new CustomDialog.Builder(activity);
builder.setTitle(R.string.app_name1);
//builder.setCancelable(true);
builder.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
accept(preferences);
/*if(activity instanceof OnEulaAgreedTo)
{
((OnEulaAgreedTo) activity).onEulaAgreedTo();
}*/
dialog.dismiss();
}
});
builder.setNegativeButton(R.string.eula_refuse, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which) {
refuse(activity);
}
});
CharSequence s = readEula(activity);
builder.setMessage(s.toString());
builder.create().show();
return false;
}
return true;
}
private static void accept(SharedPreferences preferences) {
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true).commit();
}
private static void refuse(Activity activity) {
activity.finish();
}
private static CharSequence readEula(Activity activity) {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(activity.getAssets().open(ASSET_EULA)));
String line;
StringBuilder buffer = new StringBuilder();
while ((line = in.readLine()) != null) buffer.append(line).append('\n');
return buffer;
} catch (IOException e) {
return "";
} finally {
closeStream(in);
}
}
private static void closeStream(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
}
}
And then i have my CustomDialog file
//my CustomDialog.java file...
public class CustomDialog extends Dialog {
private static final String ASSET_EULA = "EULA";
public CustomDialog(Context context, int theme) {
super(context, theme);
}
public CustomDialog(Context context) {
super(context);
}
public static class Builder {
private Context context;
private String title;
private String message;
private String positiveButtonText;
private String negativeButtonText;
//private String cancelButtonText;
private View contentView;
private DialogInterface.OnClickListener
positiveButtonClickListener,
negativeButtonClickListener;
public Builder(Context context) {
this.context = context;
}
public Builder setMessage(String message) {
this.message = message;
return this;
}
public Builder setMessage(int message) {
this.message = (String) context.getText(message);
return this;
}
public Builder setTitle(int title) {
this.title = (String) context.getText(title);
return this;
}
public Builder setTitle(String title) {
this.title = title;
return this;
}
public Builder setContentView(View v) {
this.contentView = v;
return this;
}
public Builder setPositiveButton(int positiveButtonText,
DialogInterface.OnClickListener listener) {
this.positiveButtonText = (String) context
.getText(positiveButtonText);
this.positiveButtonClickListener = listener;
return this;
}
public Builder setPositiveButton(String positiveButtonText,
DialogInterface.OnClickListener listener) {
this.positiveButtonText = positiveButtonText;
this.positiveButtonClickListener = listener;
return this;
}
public Builder setNegativeButton(int negativeButtonText,
DialogInterface.OnClickListener listener) {
this.negativeButtonText = (String) context
.getText(negativeButtonText);
this.negativeButtonClickListener = listener;
return this;
}
public Builder setNegativeButton(String negativeButtonText,
DialogInterface.OnClickListener listener) {
this.negativeButtonText = negativeButtonText;
this.negativeButtonClickListener = listener;
return this;
}
public CustomDialog create() {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// instantiate the dialog with the custom Theme
final CustomDialog dialog = new CustomDialog(context,
R.style.Dialog);
View layout = inflater.inflate(R.layout.dialog, null);
dialog.addContentView(layout, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
// set the dialog title
((TextView) layout.findViewById(R.id.title)).setText(title);
// set the confirm button
if (positiveButtonText != null)
{
((Button) layout.findViewById(R.id.positiveButton)).setText(positiveButtonText);
if (positiveButtonClickListener != null)
{
((Button) layout.findViewById(R.id.positiveButton)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
positiveButtonClickListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
}
});
}
} else {
// if no confirm button just set the visibility to GONE
layout.findViewById(R.id.positiveButton).setVisibility(
View.GONE);
}
// set the cancel button
if (negativeButtonText != null) {
((Button) layout.findViewById(R.id.negativeButton))
.setText(negativeButtonText);
if (negativeButtonClickListener != null) {
((Button) layout.findViewById(R.id.negativeButton))
.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
negativeButtonClickListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
});
}
} else {
// if no confirm button just set the visibility to GONE
layout.findViewById(R.id.negativeButton).setVisibility(
View.GONE);
}
// set the content message
if (message != null) {
((TextView) layout.findViewById(
R.id.message)).setText(message);
} else if (contentView != null) {
// if no message set
// add the contentView to the dialog body
((LinearLayout) layout.findViewById(R.id.content))
.removeAllViews();
((LinearLayout) layout.findViewById(R.id.content))
.addView(contentView,
new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
dialog.setContentView(layout);
return dialog;
}
public void dismiss()
{
this.dismiss();
}
public void setCancelable(boolean b) {
// TODO Auto-generated method stub
this.setCancelable(true);
}
}
}
Atfirst, the onClickfor setPositive button for eula.java file was like
public void onClick(DialogInterface dialog, int which)
{
accept(preferences);
if(activity instanceof OnEulaAgreedTo)
{
((OnEulaAgreedTo) activity).onEulaAgreedTo();
}
}
it worked fine for the inbuilt AlertDialog. but when i changed it with my custom dialog, that codition is resulting false always...
Can anyone tell me what that code is meant for?
For dialog disappearing you should use Dialog.dismiss(). You can dismiss dialog just at the end of positive button behavior.
When you click on refuse button you finish activity, and that's why you dialog dismisses.
The issue may be in the following condition. please check the activity instance whether it agrres the condition?
if(activity instanceof OnEulaAgreedTo)
{
((OnEulaAgreedTo) activity).onEulaAgreedTo();
}
I added a custom menu to the menu button using the following code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
if (getDisplayedView() instanceof WorkspaceView) {
((WorkspaceView) getDisplayedView()).showEditMenu();
}
return true;
}
and
public void showEditMenu() {
new EditMenu(lexs, ((Project) projects.getSelectedItem()).getName(), ((ProjectList) projectsList.getSelectedItem()).getName()).show();
}
The EditMenu is implemented the following way:
public class EditMenu {
private final String DELETE_PROJECT = "Projekt löschen";
private final String DELETE_LIST = "Liste löschen";
private final String RENAME_PROJECT = "Projekt umbenennen";
private final String RENAME_LIST = "Liste umbenennen";
private final String CLOSE = "Menü schliessen";
private Context context;
private String projectName;
private String listName;
private AlertDialog alert;
private final CharSequence[] items = {DELETE_PROJECT, DELETE_LIST, RENAME_PROJECT, RENAME_LIST, CLOSE};
public EditMenu(Context context, String projectName, String listName) {
this.context = context;
this.projectName = projectName;
this.listName = listName;
}
public void show() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(projectName + ": " + listName);
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (items[item].equals(DELETE_PROJECT)) {
deleteProject();
} else if (items[item].equals(DELETE_LIST)) {
deleteList();
} else if (items[item].equals(RENAME_PROJECT)) {
renameProject();
} else if (items[item].equals(RENAME_LIST)) {
renameList();
} else if (items[item].equals(CLOSE)) {
close();
}
}
});
alert = builder.create();
alert.show();
}
private void deleteProject() {
}
private void deleteList() {
}
private void renameProject() {
}
private void renameList() {
}
private void close() {
}
}
This works correctly if I click the menu button the first time. But if the context menu is closed and i click the menu button a second time, nothing happens.
I also tried to call
alert.close(), alert.hide(), alert.dismiss(), etc in the method close(), but it doesn't improve the situation. any hints? thankS¨!
Since there is no other answer in almost 3 weeks, I'll answer my question by myself:
Instead of overwriting
public boolean onCreateOptionsMenu(Menu menu)
one has to override
public boolean onPrepareOptionsMenu(Menu menu)
Here a short example how to do it:
In the activity there is the following code:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
showMenu();
return true;
}
private void showMenu() {
EditMenu menu = new EditMenu(this, "Pacman Menu");
menu.show();
}
Then the clsas EditMenu looks for example the following way:
public class EditMenu {
private final String QUIT = "Quit";
private final String RESTART = "New Game";
private final String SOUND = "Switch Sound";
private final String PAUSE = "Un/pause";
private final CharSequence[] items = new CharSequence[] {QUIT, RESTART, SOUND, PAUSE};
private Context context;
private String title;
private AlertDialog alert;
private MenuListener listener = new MenuListener();
public EditMenu(Context context, String title) {
this.context = context;
this.title = title;
}
public void show() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.splashscreen);
builder.setTitle(title);
builder.setItems(items, listener);
alert = builder.create();
alert.show();
}
private class MenuListener implements DialogInterface.OnClickListener {
#Override
public void onClick(DialogInterface dialog, int item) {
if (items[item].equals(QUIT)) {
((PacmanGame) context).quitGame();
} else if (items[item].equals(RESTART)) {
((PacmanGame) context).restart();
} else if (items[item].equals(SOUND)) {
Sound.setSoundOn(! Sound.isSoundOn());
} else if (items[item].equals(PAUSE)) {
((PacmanGame) context).getGameBoard().setPausing(!(((PacmanGame) context).getGameBoard().isPaused()));
}
}
}
}