I have been following Android sample provided with the documentation to design new (relatively simple) keyboard. At this point I am stuck with configuration change (like theme, textSize or bit complex stuff) which requires IME to recreate itself.
public class ImePreferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme_WithActionBar);
super.onCreate(savedInstanceState);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// reload ime
Log.d("anbani", "Stopping service " + String.valueOf(stopService(new Intent(this, SoftKeyboard.class))));
Log.d("anbani", "prefs changed");
}
...
}
This does not help. StopService value is returned true but there is no effect.
Is there some trick to get an instance of package keyboard without prior reference to it? Or am missing something simple here?
Any tips would be highly appreciated!
Solution:
#Override public View onCreateInputView() {
// load preferences
return mInputView;
}
#Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
super.onStartInputView(attribute, restarting);
setInputView(onCreateInputView());
...
}
Related
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 !
In my application, I pass a job into the job-queue and in my Job queue, I've registered my EventBus and I am trying to post the event with the hopes that my subscriber method would receive it. I have just recently migrated from Otto's EventBus and while this way had previously worked, it is not working for greenrobots EventBus 3.
Here is a sample case for what I'm trying to achieve:
TestPresenterImpl.class (This class has been instantiated the TestActivity.class)
#Override
public void addJob(JobData jobData) {
jobManager.addJobInBackground(new SendUpdateJob(jobData));
}
#Subscribe
#Override
public void onUpdate(JobAddedEvent event) {
if (event.getStatus() == 1) {
Log.i(LOG_TAG, "test");
}
}
#Override
public void onStart() {
mBus.getDefault().register(this);
}
#Override
public void onStop() {
mBus.getDefault().unregister(this);
}
SendUpdateJob.class (This is the class that handles the jobs in the queue using the android-priority-job queue previously maintained by Path)
#Override
public void onAdded() {
Log.i(LOG_TAG, "On added");
mBus.getDefault().register(this);
JobAddedEvent event = new JobAddedEvent();
event.setStatus(1);
mBus.getDefault().post(event);
}
Normally this works on Otto but since this is a slightly different, I want to know what I'm doing incorrectly. The error I get is: ..."SendJobUpdate and its super classes have no public methods with the #Subscribe annotation". Am I doing something wrong here?
I've also made sure that I'm importing import org.greenrobot.eventbus.Subscribe;
because I've noticed others have pointed out that they have imported googles subscribe.
Your EventBus.getDefault().register(this); should follow your Activity which your #Subscribe method is in, not in mBus.getDefault().post(event); Activity.
FirstActicity
public class FirstActicity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//register should in this activity
EventBus.getDefault().register(this);
}
#Subscribe(threadMode = ThreadMode.MainThread)
public void onEvent(MessageEvent event) {
//eventbus notify
Log.i("2hh", "main --- eventbus ---- updatedata");
queryData();
}
#Override
protected void onDestroy() {
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
SecondActivity(don't register in this activity beacuse you didn't hava any #Subscribe method)
public class SecondActivity extends AppCompatActivity implements{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
EventBus.getDefault().post(new MessageEvent("updateData"));
}
}
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;
}
}
I would like to call a function from my main activity class after my preferences are updated, but I can't use onResume() because I have other classes that will trigger onResume (I believe).
Snippet from AndroidGPSTrackingActivity.java:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
}
return false;
}
SettingsActivity.java:
package com.example.gpstracking;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
After my preferences close, I want to call a function from my Main Activity, however it MUST be from my main activity because I need to send a context from my Main Activity. I've tried so much and just can't seem to get it.
onResume() is triggered when the Activity comes to the foreground. You should never be "triggering" onResume() other than leaving/returning to the Activity (if you're ever directly calling onResume(), you're doing it wrong).
Assuming you're needing to check for the updated value when you return to your Activity, then yes, onResume() is where you should probably do that. If the user returns to MainActivity after viewing SettingsActivity, then onResume() will be called, and you can check the updated preference value there.
EDIT: So I think honestly you'd be better off checking the preference values in onResume(), and not caching them globally. They aren't expensive to look up. Also, for immediate notifications, you could register a listener for preference changes, like so:
public class MainActivity extends Activity
implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerPreferenceListener();
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterPreferenceListener();
}
private void registerPreferenceListener() {
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
}
private void unregisterPreferenceListener() {
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if ("the_key_i'm_interested_in".equals(key)) {
// Update stuff
}
}
}
A button triggers an action that should only be invoked once. The button is disabled and hidden in the onClick handler before the action is performed:
someButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
someButton.setEnabled(false);
someButton.setClickable(false);
someButton.setVisibility(View.GONE);
performTaskOnce();
}
});
private void performTaskOnce() {
Log.i("myapp", "Performing task");
//Do something nontrivial that takes a few ms (like changing the view hierarchy)
}
Even though the button is disabled immediately, it is nonetheless possible to trigger multiple "onClick" events by tapping multiple times very quickly. (i.e. performTaskOnce is called multiple times). Is seems that the onClick events are queued before the the button is actually disabled.
I could fix the problem by checking in every single onClick handle whether the corresponding button is already disabled but that seems like a hack. Is there any better way to avoid this issue?
The problem occurs on Android 2.3.6, I cannot reproduce it on Android 4.0.3. But given the rarity of 4.x devices it is not an option to exclude older devices.
You could set a boolean variable to true when the button is clicked and set it to false when you're done processing the click.
This way you can ignore multiple clicks and not having to disable the button possibly avoiding annoying flickering of the button.
boolean processClick=true;
someButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(processClick)
{
someButton.setEnabled(false);
someButton.setClickable(false);
someButton.setVisibility(View.GONE);
performTaskOnce();
}
processClick=false;
}
});
private void performTaskOnce() {
Log.i("myapp", "Performing task");
//Do something nontrivial that takes a few ms (like changing the view hierarchy)
}
In the interest of keeping DRY:
// Implementation
public abstract class OneShotClickListener implements View.OnClickListener {
private boolean hasClicked;
#Override public final void onClick(View v) {
if (!hasClicked) {
onClicked(v);
hasClicked = true;
}
}
public abstract void onClicked(View v);
}
// Usage example
public class MyActivity extends Activity {
private View myView;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView.setOnClickListener(new OneShotClickListener() {
#Override public void onClicked(View v) {
// do clicky stuff
}
});
}
}
Bit late but this might be of use to someone. In my case I am calling another activity so;
Declare a boolean;
boolean clickable;
In the click listener;
if(clickable){
// Launch other activity
clickable = false;
}
Enable when onResume is called;
#Override
public void onResume() {
Log.e(TAG, "onResume");
super.onResume();
clickable = true;
}
You can use RxView(com.jakewharton.rxbinding2.view.RxView) is an extension around RxJava that created by Jake Wharton.
To integrate it to project you should use implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0'
Simple Java usage:
RxView.clicks(yourButton)
.sample(500, TimeUnit.MILLISECONDS)
.subscribe { action() }
In Kotlin you can create extension function to handle your clicks:
View.singleClick(action: () -> Any) {
RxView.clicks(this)
.sample(500, TimeUnit.MILLISECONDS)
.subscribe { action() }
}
Sample:
Kotlin
yourButton.singleClick({
//do some stuff here
})
Java
SingleClickListenerKt.singleClick(yourButton, () -> {
doSomeStuff();
return null;
});
Note: you can use any RxJava operators like debounce, map, first, etc if you wish.
declare a varieble
and use it as
boolean boo = false;
someButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(boo==false){
someButton.setEnabled(false);
someButton.setClickable(false);
someButton.setVisibility(View.GONE);
boo = true;
}
}
});
by this you prevent multiple clicks on your button
hope it help