I am trying to make listener interface between two activities Act1 and Act2. Act1 will start Act2. If there is some event occurred in Act2, it will inform it to Act1. Problem is that I am starting new activity using Intent, so how Act1 will assign itself as listener to Act2's interface?
Act1.java
public class Act1 extends ActionBarActivity implements
ActionBar.OnNavigationListener {
ActionBar actionbar;
Intent pizzaIntent;
boolean visibleFirstTime = true;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menutab);
//set actionbar here
}
#Override
public boolean onNavigationItemSelected(int arg0, long arg1)// item pos,
// itemid
{
switch (arg0) {
case 0:
if(this.visibleFirstTime == false)
{
if(pizzaIntent == null)
{
pizzaIntent = new Intent(this,Act2.class);
//how to call setChangeListener?
}
startActivity(pizzaIntent);
}
else
this.visibleFirstTime = false;
break;
case 1:
System.out.println("selected: " + arg0);
break;
case 2:
System.out.println("selected: " + arg0);
break;
case 3:
System.out.println("selected: " + arg0);
break;
default:
break;
}
return true;
}
}
Act2.java
public class Act2 extends Activity {
selectionChangeListener listener;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pizza_slice_selection);
}
public void setChangeListener(selectionChangeListener listener)
{
this.listener = listener;
}
private interface selectionChangeListener
{
public void selectionMadeAtIndex(int index);
}
}
Note: Please don't suggest me to use fragments. I want to use activities currently.
I would suggest to create a model class. Let me give you an example:
Model class:
public class CustomModel {
public interface OnCustomStateListener {
void stateChanged();
}
private static CustomModel mInstance;
private OnCustomStateListener mListener;
private boolean mState;
private CustomModel() {}
public static CustomModel getInstance() {
if(mInstance == null) {
mInstance = new CustomModel();
}
return mInstance;
}
public void setListener(OnCustomStateListener listener) {
mListener = listener;
}
public void changeState(boolean state) {
if(mListener != null) {
mState = state;
notifyStateChange();
}
}
public boolean getState() {
return mState;
}
private void notifyStateChange() {
mListener.stateChanged();
}
}
And here's how you would use this:
// Imports
public class MainActivity extends Activity implements OnCustomStateListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomModel.getInstance().setListener(this);
boolean modelState = CustomModel.getInstance().getState();
Log.d(TAG, "Current state: " + String.valueOf(modelState));
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
#Override
public void stateChanged() {
boolean modelState = CustomModel.getInstance().getState();
Log.d(TAG, "MainActivity says: Model state changed: " +
String.valueOf(modelState));
}
}
Changing the member state in second activity:
// Imports
public class SecondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomModel.getInstance().changeState(true);
}
}
LogCat output:
Current state: false
MainActivity says: Model state changed: true
Have you considered using LocalBroadcastManager?
In Act1's onCreate:
act2InitReceiver= new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// do your listener event stuff
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(act2InitReceiver, new IntentFilter("activity-2-initialized"));
In Act1's onDestroy:
LocalBroadcastManager.getInstance(this).unregisterReceiver(act2InitReceiver);
In Act2's onCreate:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("activity-2-initialized"));
Give me a comment if the code doesn't compile, I'm writing it by hand.
The best, shortest and the easiest way to do this is to use static variables, like this:
class Main extends Activity {
static String message = "Hi";
}
class Another extends Activity {
public onCreate() {
Log.i(Main.message); // implementation of the message, 'Hi'
}
}
Related
I create an application with MVVM concept, there is fragment for viewpager in my Activity. some data changed when I change my language in my application, but the data that showed by webservices is not change. so I try to add android:configChanges="locale" in my every Activity and I already add this code on my Activity class :
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
recreate();
}
}
But its make my UI recreate every configuration change, including Screen Rotation while I just want to recreate if Language is changed.
this is my fragment code :
public class CatalogueFragment extends BaseFragment<FragmentCatalogueBinding, CatalogueViewModel>
implements CatalogueNavigator, CatalogueAdapter.CatalogueAdapterListener {
#Inject
CatalogueAdapter adapter;
#Inject
LinearLayoutManager mLayoutManager;
#Inject
ViewModelProvider.Factory factory;
FragmentCatalogueBinding fragmentCatalogueBinding;
private CatalogueViewModel catalogueViewModel;
public static CatalogueFragment newInstance(int Pos) {
Bundle args = new Bundle();
CatalogueFragment fragment = new CatalogueFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public int getBindingVariable() {
return BR.viewModel;
}
#Override
public int getLayoutId() {
return R.layout.fragment_catalogue;
}
#Override
public CatalogueViewModel getViewModel() {
catalogueViewModel = ViewModelProviders.of(this, factory).get(CatalogueViewModel.class);
return catalogueViewModel;
}
#Override
public void handleError(String error) {
// handle error
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
catalogueViewModel.setNavigator(this);
adapter.setListener(this);
}
#Override
public void onRetryClick() {
catalogueViewModel.fetchData();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fragmentCatalogueBinding = getViewDataBinding();
setUp();
}
#Override
public void updateData(List<Movie> movieList) {
adapter.addItems(movieList);
}
private void setUp() {
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
fragmentCatalogueBinding.recyclerCatalogue.setLayoutManager(mLayoutManager);
fragmentCatalogueBinding.recyclerCatalogue.setItemAnimator(new DefaultItemAnimator());
fragmentCatalogueBinding.recyclerCatalogue.setAdapter(adapter);
}
}
and this is my ViewModel class
public class CatalogueViewModel extends BaseViewModel {
private final MutableLiveData<List<Movie>> movieListLiveData;
public CatalogueViewModel(DataManager dataManager, SchedulerProvider schedulerProvider) {
super(dataManager, schedulerProvider);
movieListLiveData = new MutableLiveData<>();
fetchData();
}
public void fetchData() {
setIsLoading(true);
getCompositeDisposable().add(getDataManager()
.getApiHelper().doMovieCall(URLConfig.API_KEY, getDataManager().getLanguage())
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(movieResponse -> {
if (movieResponse != null && movieResponse.getResults() != null) {
movieListLiveData.setValue(movieResponse.getResults());
}
setIsLoading(false);
}, throwable -> {
setIsLoading(false);
// getNavigator().handleError(throwable);
}));
}
public LiveData<List<Movie>> getMovieListLiveData() {
return movieListLiveData;
}
}
Can anybody show me where is my wrong? Thank you very much
You can use: ACTION_LOCALE_CHANGED
Here an example:
private BroadcastReceiver mLangReceiver = null;
protected BroadcastReceiver setupLangReceiver(){
if(mLangReceiver == null) {
mLangReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do what you want
}
};
registerReceiver(mLangReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
}
return mLangReceiver;
}
I am trying to create a class which can be called from any activity to speak the text from an EditText box. When I run the code I currently have, it plays the alert sound but then fails to play the Text to Speech content. What do I need to change to get the text to play too? I know the activity layout XML code is correct because the Text To Speech code works when it is directly in the activity class. I have looked around for a solution but nowhere else outlines how to do this from a thread context.
I have included my code below:
on AircraftMain.java
View.OnClickListener speakBtnOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View arg0) {
String toSpeak = textToSpeak.getText().toString();
TextToSpeak speak = new TextToSpeak(AircraftMain.this, toSpeak);
speak.run();
}
};
TextToSpeak.java
import android.app.Activity;
import android.media.MediaPlayer;
import android.speech.tts.TextToSpeech;
import java.util.Locale;
public class TextToSpeak implements Runnable {
private Activity activity;
private static String text;
private static TextToSpeech talk;
public TextToSpeak(Activity activity, String toSpeak) {
this.activity = activity;
text = toSpeak;
}
public void run() {
talk = new TextToSpeech(activity, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
talk.setLanguage(Locale.UK);
}
}
});
talk.addEarcon("Attention", "com.kieronmc.aircraftgps", R.raw.warning_beep);
talk.playEarcon("Attention", QUEUE_ADD,null);
talk.setLanguage(Locale.UK);
talk.speak(text, TextToSpeech.QUEUE_ADD, null);
}
}
Try this code, It should work:
1) Create a text to speech Initializer as follows:
public class TextToSpeechInitializer{
private Context context;
private static TextToSpeech talk;
private TextToSpeechIniListener callback;
private Locale locale;
public TextToSpeechInitializer(Context context , Locale locale , TextToSpeechIniListener l) {
this.context = context;
if(l != null) {
callback = l;
}
this.locale = locale;
initialize();
}
private void initialize() {
talk = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
talk.setLanguage(locale); //TODO: Check if locale is available before setting.
callback.onSucces(talk);
}else{
callback.onFailure(talk);
Log.e("TTS","TextToSpeechInitializeError");
}
}
});
}
}
2) The above initializer class calls this interface class to notify the activity below (TTS Success or Failure) :
public interface TextToSpeechIniListener {
public void onSucces(TextToSpeech tts);
public void onFailure(TextToSpeech tts);
}
3) Activity
public class Demo7 extends AppCompatActivity implements TextToSpeechIniListener {
private Button b;
private TextToSpeechInitializer i;
private TextToSpeech talk;
private boolean flag = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo7);
i = new TextToSpeechInitializer(this, Locale.UK, this);
b = (Button) findViewById(R.id.b);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(flag) {
talk.addEarcon("Attention", getPackageName(), R.raw.androidcalm);
talk.playEarcon("Attention", QUEUE_ADD, null);
//talk.setLanguage(Locale.UK);
talk.speak("Hello, Testing", QUEUE_ADD, null);
}
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
if(talk != null){
talk.stop();
talk.shutdown();
}
}
#Override
public void onSucces(TextToSpeech tts) {
this.talk = tts;
flag = true;
}
#Override
public void onFailure(TextToSpeech tts) {
flag = false;
finish();
}
}
layout demo7.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:gravity="center">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/b"
android:text="speak"/>
</LinearLayout>
I'm trying using ReferenceQueue to check Activity if the activity is destory,Whether this activity is recycled.
I just using intent to Main2Activity.class:
switch (v.getId()){
case R.id.btn_turn_two:
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
break;
default:
break;
}
when I press to return MainActivity.class, the Main2Acitivity.class will be destroyed, so I using registerActivityLifecycleCallbacks watch activity in application,
public class MainApplication extends Application{
private watche watche;
#Override
public void onCreate() {
super.onCreate();
watche=new watche(this,getApplicationContext());
}
this class is check the Activity is destoryed.
public class watche {
KeyRefrence ref;
private Context context;
private final Set<String> retainedKeys = new CopyOnWriteArraySet<>();
private final ReferenceQueue<Object> referenceQueue=new ReferenceQueue<>();
public watche(Application application, Context context){
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
this.context=context;
}
Application.ActivityLifecycleCallbacks lifecycleCallbacks=new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
//weakrefrence to this activity
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyRefrence weakReference=new KeyRefrence(activity,key,activity.getPackageName(),referenceQueue);
final MyAyTask myAyTask=new MyAyTask(weakReference,activity,context);
myAyTask.doInBackground(null);
}
};
public class MyAyTask extends AsyncTask {
private Activity activity;
private KeyRefrence keyRefrence;
private Context context;
public MyAyTask(KeyRefrence keyRefrence, Activity activity,Context context){
this.activity=activity;
this.context=context;
this.keyRefrence=keyRefrence;
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
}
#Override
protected Object doInBackground(Object[] objects) {
gc();
ref=(KeyRefrence)referenceQueue.poll();
if (ref==null){
Log.d(TAG, "onActivityDestroyed:Acitivty is not destory");
}
else if (ref!=null){
Log.d(TAG, "doInBackground: "+ref);
}
return null;
}
}
I have create KeyReference implement WeakReference,and I didn't do anything in Main2Activity.class, I just press the phone return,I check the gc,is working ,but the referencequeue always empty, I'm sure the Activity is destoryed.
How should I fetch value of a Checkbox which is in an Activity and in its onCreate there is findviewbyId method.
public class abc extends Activity {
Checkbox mon;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_xml);
mon = (CheckBox)findViewById(R.id.checkbox_mon);
}
public boolean check()
{
if (mon.isChecked())
return true;
else
return false;
}}
Now, there is another java class, in which I am passing the activity class object and calling that method which returns the value.
abc a =new abc();
a.check();
But it is not working. I think there is problem with findviewbyid statement.
And also, if the acitivity is not being opened , I want it to show the defualt value which I set in the xml file
android:checked="false"
Set a static variable and assign the value of CheckBox:
public class abc extends Activity {
Checkbox mon;
public static boolean checkBoxValue; //here
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_xml);
mon = (CheckBox)findViewById(R.id.checkbox_mon);
}
public boolean check()
{
if (mon.isChecked())
checkBoxValue = true; //here
return true;
else
checkBoxValue = false; //here
}}
Another class:
public class AnotherClass {
.....
public boolean value = abc.checkBoxValue;
.......
}
Another way
abc Activity:
public boolean check()
{
if (mon.isChecked())
Intent intent = new Intent(this, anotherClass.class);
intent.putExtra("value", true);
startActivity(intent);
return true;
.....
.......
another Activty:
public class AnotherClass extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.anotherclass);
boolean value = getIntent().getBooleanExtra("value");
}
}
Boolean with static modifier would be enough for your case.
public static boolean monValue = false // as you mention the default is false
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.my_xml);
mon = (CheckBox)findViewById(R.id.checkbox_mon);
mon.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton btn, boolean b) {
monValue = b;
}
});
}
Then you just need to boolean x = abc.monValue in other class.
But I really want to suggest another way to communicate between class within android lifecycle.
With EventBus
Create class that wraps event data
public class MyCheckboxEvent {
public final boolean checked;
public MyCheckboxEvent(boolean checked) {
this.checked = checked;
}
}
Then add EventBus.getDefault().post(new MyCheckboxEvent(booleanValue)); on you abc activity
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.my_xml);
mon = (CheckBox)findViewById(R.id.checkbox_mon);
mon.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton btn, boolean b) {
EventBus.getDefault().post(new MyCheckboxEvent(b));
}
});
}
Add the handler on any class that subscribe the abc Checkbox event data
#Subscribe
public void handleMyAbcCheckbox(MyCheckboxEvent event) {
boolean x = event.checked;
}
Then register and unregister the subscriber according to the lifecycle
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
I have a problem with code. I have two classes: MainActivity where i checking if sensor (in this case light sensor) is available and if yes - i try to get date from sensor from another class LightSensor, but result is always null. I think that i'm doing something wrong with listener but i don't know what.. and i'm sitting on this couple of hours and still nothing.. If you have any idea, please write and help me.
MainActivity class:
`public class MainActivity extends Activity implements EventListener {
SensorManager mSensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView wyswietl = (TextView)findViewById(R.id.res);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
LightSensor mLightSensor = new LightSensor(getBaseContext());
if (mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) != null){
//mLightSensor.register();
String newLux = mLightSensor.getLux();
wyswietl.setText("Light level: " + newLux);
}
else{
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}`
and in MainActivioty class i don't know it argument in constructor :
LightSensor mLightSensor = new LightSensor(getBaseContext()); is good...
LightSensor class:
`public class LightSensor implements SensorEventListener {
public SensorManager mSensorManagerx;
public Sensor lightManager;
public String lux;
Context context;
public LightSensor(Context context){
//public void onCreateLight(Context context){
this.context = context;
mSensorManagerx = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
lightManager = mSensorManagerx.getDefaultSensor(Sensor.TYPE_LIGHT);
}
public void register(){
mSensorManagerx.registerListener(this, lightManager, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
lux = Float.toString(event.values[0]);
}
public String getLux(){
return lux;
}
public void unregister(){
mSensorManagerx.unregisterListener(this);
}
}`
You should not use a getter for this purpose, because the value your getting will be initialized after a unknown time. So it could still be null when you're calling the getLux method.
What you should do is use a listener pattern. I have changed your code a bit to give you an example implementation.
LightSensor:
public class LightSensor implements SensorEventListener {
public static interface LightSensorListener {
abstract void onLightSensorChanged(String lux);
}
private LightSensorListener listener;
private SensorManager mSensorManagerx;
private Sensor lightManager;
public LightSensor(Context context) {
mSensorManagerx = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
lightManager = mSensorManagerx.getDefaultSensor(Sensor.TYPE_LIGHT);
}
public void setListener(LightSensorListener listener) {
this.listener = listener;
}
public boolean register() {
return mSensorManagerx.registerListener(this, lightManager, SensorManager.SENSOR_DELAY_UI);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public void onSensorChanged(SensorEvent event) {
if (listener != null) {
listener.onLightSensorChanged(Float.toString(event.values[0]));
}
}
public void unregister() {
mSensorManagerx.unregisterListener(this);
}
}
Activity:
public class ActivityLightSensor extends Activity implements LightSensorListener {
private TextView text;
private LightSensor mLightSensor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.test);
mLightSensor = new LightSensor(getBaseContext());
mLightSensor.setListener(this);
}
#Override
public void onLightSensorChanged(String lux){
text.setText("Light level: " + lux);
}
#Override
protected void onResume() {
super.onStart();
if(!mLightSensor.register()){
Toast.makeText(this, "Light sensor not supported!", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onPause() {
super.onStop();
mLightSensor.unregister();
}
}
onSensorChanged event is not called just after you created listener. It is called after something will change sensot value, then it will be called. So you should implement some callback, or, as for me, better would be to implement SensorEventListener in your activity, then just in onSensorChanged event method call
wyswietl.setText("Light level: " + newLux);