Modify elements of a layout from another class - java

I am a student and a beginner in java and android.
I am modifying an android application which allows to configure bluetooth beacons. With the original application we can only configure the beacons one by one, therefore I want to modify the application to be able to configure a good number automatically.
I have a problem when I want to modify an element in the layout of a class from another class.
From the Main class I can interact well with the elements of the Main layout. But since the Main class, I can't interact with other layouts (PasswordDialog in my case). I've been struggling for several days, I tried responses to similar posts but without success because the configuration of my classes is quite special and I don't want to modify them too much so as not to alter the functioning of the application. If anyone has any leads, I would be very grateful;)
The main class:
public class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener, MokoScanDeviceCallback, AdapterView.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ...
final PasswordDialog dialog = new PasswordDialog(this); // Another function which already calls the PasswordDialog class which interests me
dialog.setSavedPassword(mSavedPassword);
dialog.setOnPasswordClicked(new PasswordDialog.PasswordClickListener() {
// ...
}
}
#OnClick({R.id.iv_about, R.id.iv_refresh, R.id.bt_auto})
public void onClick(View view) {
switch (view.getId()) {
// ...
case R.id.bt_auto: // When I click on the bt_auto button, the code below is executed
final PasswordDialog dialog = new PasswordDialog(this);
dialog.AutoSetPassword("Moko4321"); // the method I'm trying to launch
// ...
}
}
// ...
}
Now here is the PasswordDialog class which is in another package. I want to modify an element of the passworddialog layout from my Main class :
public class PasswordDialog extends BaseDialog {
#Bind(R.id.et_password)
EditText etPassword; // The element that I want to modify
public PasswordDialog(Context context) {
super(context);
}
// ...
public void AutoSetPassword(String pass) { // My method to modify the EditText
etPassword.setText(pass); // This does not work
// and
((EditText) findViewById(R.id.et_password)).setText(pass); // If I try this instead, it's the same
}
}
Thank you so much for your help :)

Related

ANDROID: Update data in another activity in Master Detail Flow Layout

I've searched for a solution for my question all over the internet but I haven't been able to find one and I hope you can help me out
I am trying to create a master detail flow application in android with 2 activities and the second activity contains a fragment. Can anyone please tell me how I can simultaneously update the value in the MainActivity() when I make a change in the fragment's EditText field? I have tried using an Intent but when the 2 activities are side by side that doesnt seem to work well.
Screenshot of Emulator
Any suggestions?
It seems you are in a context as follows:
When A happens, it triggers B
As a result, I suggest you to use EventBus library in your project.
The installation is easy. First, add the following code in your build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Second, let's see what we are going to add in our codes.
In the Fragment which you wanted to make changes:
/* When A happens */
myButton.setOnClickListener(new View.OnClickListener() { // complete entering the content, update it
EventBus.getDefault.post(MyUpdateEvent(myContent));
});
Create your custom class MyUpdateEven:
public class MyUpdateEvent{
private String myContent;
public MyUpdateEvent(String myContent) {
this.myContent = myContent;
}
public String getUpdateContent() {
return myContent;
}
}
In the Activity you wanted to update:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault.register(this); // add this code to monitor the update
}
/* It triggers B */
#Subscribe // don't forget to add #Subscribe
public void onEvent(MyUpdateEvent event){
// this is your custom method
myTextView.setText(event.getUpdateContent()); // do your update
}
#Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault.unregister(this); // when you leave this lifecycle, cancel the monitoring
}
}
EventBus is a good library that I've been used a lot in my projects.
I think it can solve your problem.
Try to define a interface.
public interface OnEditActivity {
public void onEdit(ActivityObject activityObject, boolean isEditing);
}
And on your another class for example DetailActivity, then you have to override the method onEdit that you created in your interface:
public class DetailActivity extends AppCompatActivity implements OnEditActivity{
//IN HERE --- Create method.
#Override
public void onEdit(ActivityObject activityObject, boolean isEditing) {
if(isEditing){
displayView(activityObject,true);
}else{
displayView(activityObject,false);
}
}
}
And in your EditFragment for example will look like this:
public class EditFragment extends Fragment{
//Define your interface in your fragment
private OnEditActivity onEditActivity;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_edit_activity, container, false);
return v;
}
public void onAttach(Activity a) {
super.onAttach(a);
onEditActivity =(OnEditActivity) a;
}
}
And if you want to call onEdit method just call:
onEditActivity.onEdit(activityObjectNew,false)
I hope this help you !

How to manage a DialogFragment with RxJava?

I've been trying to determine if it's possible to create an observable DialogFragment. Essentially I want to be able to:
Create and show a DialogFragment
Get back an rx Observable which can be subscribed to for the result (ok/cancel pressed, String input, background task success/failure, etc.)
Properly handle configuration change
So far the closest thing I've found is ReactiveDialog, which used to be part of RxAndroid, but has been removed from RxAndroid in v1.0.0 as a part of simplifying RxAndroid.
While ReactiveDialog does appear to meet my first two criteria, it does not appear to handle configuration change. There are two issues to consider:
The DialogFragment must maintain its Observable across configuration change so it can notify subscribers of its state.
The subscriber(s) must be able to either hold on to their subscription or re-subscribe after a configuration change (obviously without producing a memory leak).
I'm still fairly new to RxJava, so I'm still trying to wrap my head around how you would manage something like this. It seems like it should be possible, but I feel like it would require a static or singleton Observable manager and possibly retainedInstance DialogFragments.
Anyone have any suggestions or best practices for this?
There are two issues here; one is that you don't want to lose Java Objects during relayout - look into the runtime changes docs about that.
The other issue is that you want to create an Observable that has the action of the dialog, when that action is triggered. For that, have a look at the RxJava docs, the Asynchronous Observer example. You will need to create an Observable.OnSubscribe, and pass that Subscriber to your code that will call the necessary onNext/onError/onCompleted calls.
I would use a ViewModel for the dialog which helps with configuration changes. After a configuration change re-subscribe to the dialog's ViewModel.
1. Components
Screen (Activity/Fragment) - This will display the dialog fragment
DialogFragment - The dialog. Will publish updates about User's actions.
DialogViewModel - holds the User's actions stream
2. Implementation
SimpleActivity
public class SimpleActivity extends AppCompatActivity {
private SimpleDialogViewModel dialogViewModel;
private CompositeDisposable compositeDisposable;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dialogViewModel = ViewModelProviders.of(this).get(SimpleDialogViewModel.class);
compositeDisposable = new CompositeDisposable();
showDialog();
}
#Override
protected void onResume() {
super.onResume();
Disposable disposable =
dialogViewModel
.actionStream()
.subscribe(
result -> {
if (AlertDialog.BUTTON_POSITIVE == result) {
// User clicked yes
}
if (AlertDialog.BUTTON_NEGATIVE == result) {
// User clicked no
}
}
);
compositeDisposable.add(disposable);
}
#Override
protected void onPause() {
super.onPause();
compositeDisposable.clear();
}
private void showDialog() {
SimpleDialogFragment dialogFragment = new SimpleDialogFragment();
dialogFragment.show(getSupportFragmentManager(), SimpleDialogFragment.TAG);
}
}
SimpleDialogFragment
public class SimpleDialogFragment extends DialogFragment {
public static final String TAG = "SimpleDialogFragment";
private SimpleDialogViewModel dialogViewModel;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dialogViewModel = ViewModelProviders.of(getActivity()).get(SimpleDialogViewModel.class);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog_simple_message, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
final View btnYes = view.findViewById(R.id.yes);
final View btnNo = view.findViewById(R.id.no);
btnYes.setOnClickListener(v -> dialogViewModel.onClickYes());
btnNo.setOnClickListener(v -> dialogViewModel.onClickNo());
}
}
SimpleDialogViewModel
public class SimpleDialogViewModel extends ViewModel {
private Subject<Integer> actionSubject;
SimpleDialogViewModel() {
actionSubject = PublishSubject.create();
}
public void onClickYes() {
actionSubject.onNext(AlertDialog.BUTTON_POSITIVE);
}
public void onClickNo() {
actionSubject.onNext(AlertDialog.BUTTON_NEGATIVE);
}
public Observable<Integer> actionStream() {
return actionSubject;
}
}

Android: Passing Objects Between Fragments

Before i start, i have look through question such as:
Passing data between fragments: screen overlap
How to pass values between Fragments
as well as Android docs:
http://developer.android.com/training/basics/fragments/communicating.html
as well as this article:
http://manishkpr.webheavens.com/android-passing-data-between-fragments/
Though all the cases mentioned above similar to what i have, it is not entirely identical. I followed a good tutorial here (Some portion of my code is based on this article):
http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/
I have the following files:
RegisterActivity.java
NonSwipeableViewPager.java
ScreenSliderAdapter.java
RegisterOneFragment.java
RegisterTwoFragment.java
And the following layouts:
activity_register.xml
fragment_register_one.xml
fragment_register_two.xml
What i am trying to achieve is passing an Serializable object from RegisterFragmentOne to RegisterFragmentTwo.
So far this is what i have done (some codes are omitted):
RegisterActivity.java
public class RegisterActivity extends FragmentActivity
implements RegisterOneFragment.OnEmailRegisteredListener{
public static NonSwipeableViewPager viewPager;
private ScreenSliderAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
// Initilization
mAdapter = new ScreenSliderAdapter(getSupportFragmentManager());
viewPager = (NonSwipeableViewPager) findViewById(R.id.pager);
viewPager.setAdapter(mAdapter);
}
public void onEmailRegistered(int position, Registration regData){
Bundle args = new Bundle();
args.putSerializable("regData", regData);
viewPager.setCurrentItem(position, true);
}
}
ScreenSliderAdapter.java
public class ScreenSliderAdapter extends FragmentPagerAdapter{
public ScreenSliderAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new RegisterOneFragment();
case 1:
return new RegisterTwoFragment();
case 2:
return new RegisterThreeFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
NonSwipeableViewPager.java (extending ViewPager class, and overrides the following)
#Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
RegisterOneFragment.java
public class RegisterOneFragment extends Fragment {
OnEmailRegisteredListener mCallBack;
public interface OnEmailRegisteredListener {
/** Called by RegisterOneFragment when an email is registered */
public void onEmailRegistered(int position, Registration regData);
}
public void onAttach(Activity activity){
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallBack = (OnEmailRegisteredListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnEmailRegisteredListener");
}
}
... And some to execute some HTTP request via separate thread...
}
What i am trying to accomplish is that when ever a user pressed a button on RegisterOneFragment, a data will be sent to a server (and returns some validation over JSON). If the returned data is valid, the the application should go to the next fragment which is RegistrationTwoFragment.
I am having some confusion as how to pass objects between fragments, since my Fragments is created using an Adapter. And that Adapter is then attached to my Activity.
Can anyone help me with this? Thx
Edit 1:
I tried to make a shortcut (unfortunately does not work) like so:
In RegisterActivity i created:
public Registration regData;
and in RegisterOneFragment:
/* PLACED ON POST EXECUTE */
((RegisterActivity)getActivity()).regData = regData;
Finally called it in RegisterTwoFragment
Registration regData;
regData = ((RegisterActivity) getActivity()).regData;
It throws a nullPointerExceptions
Edit 2
Just to be clear, RegisterActivty contains multiple fragments. And the only way user can navigate between fragment is by clicking a button. The Activity has no Tab bar.
It's easy to share objects via implementing Serializable to your custom Object. I wrote a tutorial about this here.
From Fragment One:
android.support.v4.app.FragmentTransaction ft =
getActivity().getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
OfficeCategoryFragment frag = new OfficeCategoryFragment();
Bundle bundles = new Bundle();
Division aDivision = divisionList.get(position);
// ensure your object has not null
if (aDivision != null) {
bundles.putSerializable("aDivision", aDivision);
Log.e("aDivision", "is valid");
} else {
Log.e("aDivision", "is null");
}
frag.setArguments(bundles);
ft.replace(android.R.id.content, frag);
ft.addToBackStack(null);
ft.commit();
In Fragment two:
Bundle bundle = getArguments();
Division division= (Division) bundle.getSerializable("aDivision");
Log.e("division TEST", "" + division.getName());
I would normally have setters or methods similar to this in the containing activity.
So if I understand correctly, you want the user to access RegistrationOneFragment, then when completed, use this data, validate it, and if valid, pass it along to RegistrationTwoFragment and move the user to this Fragment.
Could you simply call validateJson(regData) in your onEmailRegistered method to handle the validation in your activity, if it succeeds, commit a transaction to RegistrationTwoFragment.
Then all you need are getters and setters in your activity or Fragment to say getRegistrationOneData() in the activity or setData(Registration args) in the fragment as your examples show above.
I don't know of any way to pass the args directly into the Fragment.
I found a solution to my question, which i am sure not the correct way to do that...
So in RegisterActivity.java i add + modified the following lines (thx to #sturrockad):
public Registration getRegistrationData(){
return this.regData;
}
public void onEmailRegistered(int position, Registration regData){
this.regData = regData;
viewPager.setCurrentItem(position, true);
}
Then in RegisterTwoFragments.java (or in the Fragment to which i want to receive the Object):
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_register_two, container, false);
regData = ((RegisterActivity) getActivity()).getRegistrationData();
...
I used to set object with Pacelable or Serializable to transfer, but whenever I add other variables to object(model), I have to register it all. It's so inconvenient.
It's super easy to transfer object between activities or fragments.
Android DataCache
put your data object to KimchiDataCache instance in your activity or fragment.
User userItem = new User(1, "KimKevin"); // Sample Model
KimchiDataCache.getInstance().put(userItem);
// add your activity or fragment
Get your data object in your activity of fragment that you added.
public class MainFragment extends Fragment{
private User userItem;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
userItem = KimchiDataCache.getInstance().get(User.class);
}

Share a fragment with several classes?

I wonder how I can best create a progress bar fragment. It must be usable by every other class of course.
At the moment I have just a ProgressBarFragment, which has public setVisible method. Getting the Fragment through FragmentManager I can set it visible or not. But is this the right way to do these sort of actions?
public class MyActivity exetends FragmentActivity {
void setVisibility(int visible) {
ProgressBarFragment fragment = (ProgressBarFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_progress_bar);
fragment.setProgressBar(visible);
}
}
And of course I have several other Fragments which uses this code too, to trigger the progress bar.
public class ProgressBarFragment extends Fragment {
public void setProgressBar(int visible) {
progressBar = (ProgressBar) getActivity().findViewById(R.id.progress_bar);
progressBar.setVisibility(visible);
}
}
You can refactor this code into a static method of your ProgressBarFragment
class ProgressBarFragment {
//...
static void setVisibility(Activity parent, int visible) {
ProgressBarFragment progressBar =
(ProgressBarFragment)parent.getSupportFragmentManager()
.findFragmentById(R.id.fragment_progress_bar);
progressBar.setProgressBar(visible);
//...
}
So then you will be using ProgressBarFragment.setVisibility(yourActivity, 1) everywhere.

Best way to store list of activities to be called from another activity

I have following goal: From a list in main activity that extends ListActivity, I want to start other activities.
This is the code of the main activity:
public class SelectionWidgetsExampleActivity extends ListActivity {
private Class[] demos = {ListViewDemo.class, ChecklistDemo.class};
private ArrayAdapter<Class> aa;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
aa = new ArrayAdapter<Class>(this, android.R.layout.simple_list_item_1, demos);
setListAdapter(aa);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(this, demos[position]);
startActivity(intent);
}
}
My question is
How would you solve the issue of having list of classes to be executed outside the code of the main activity?
My first idea was to put it into xml resource file as string array. I can then easily create array of Strings from the resource, but don't know how to convert the string to the class - I need something like:
SomeJavaClass.getMeClassFromString(demos[position])
Do you need Class#forName(String className)?
It will solve your issue.
But what's wrong with your initial (posted) solution? I'd rather keep it than use dynamic class loading, only would changed modifiers of demos to private static final.

Categories