Start activity in BroadCast Receiver causing app crash - java

I have created an application in which when I turn on bluetooth a toast is shown and a new activity starts. This is my broadcast receiver class:
public class BroadCast extends BroadcastReceiver {
String prefs="myPrefs";
String count="myCount";
static int counter=0;
Intent i;
#Override
public void onReceive(Context arg0, Intent arg1) {
String bluth = arg1.getAction();
if (bluth.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
if(arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_ON){
SharedPreferences sp = arg0.getSharedPreferences(prefs, Context.MODE_PRIVATE);
Editor ed = sp.edit();
ed.putInt(count, counter);
ed.commit();
counter++;
Toast.makeText(arg0, "Bluetooth on " + sp.getInt(count, 0), Toast.LENGTH_LONG).show();
i = new Intent(arg0, Indicators.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
arg0.startActivity(i);
Indicators.on.setVisibility(View.VISIBLE);
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_TURNING_OFF) {
} else if (arg1.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_TURNING_ON) {
}
}
}
}
Now there is no problem. The activity is starting but in the above code when I put
Indicators.on.setVisibility(View.VISIBLE);
And run the app, It crashes!
Actually on is a textview obj which I have defined in Indicators class as follows:
public class Indicators extends Activity {
static TextView on, off, opening, closing;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.textviewbluetooth);
opening = (TextView)findViewById(R.id.textView1);
on = (TextView)findViewById(R.id.textView2);
closing = (TextView)findViewById(R.id.textView3);
off = (TextView)findViewById(R.id.textView4);
opening.setVisibility(View.INVISIBLE);
on.setVisibility(View.INVISIBLE);
off.setVisibility(View.INVISIBLE);
closing.setVisibility(View.INVISIBLE);
}
}
How should I remove this error?

class YourActivity extends xxxx {
private static YourActivity mInst;
public static YOurActivity instance() {
return mInst;
}
/// Do your task here.
public void setViewText(xxxx) ;
#Override
public void onStart() {
...
mInst = this;
}
#Override
public void onStop() {
...
mInst = null;
}
}
And in your BroadcastReceiver:
YOurActivity inst = YOurActivity.instance();
if(inst != null) { // your activity can be seen, and you can update it's context
inst.setViewText...
}

Put this line
on.setVisibility(View.VISIBLE);
Inside the Activity -> onCreate() method.
Do not use static references to the Activity class members like TextViews from outside the Activity itself as it might have been destroyed, or not have been created yet. This is bad practice in general.
Edit: Add an extra to the Activity starter intent if you need a flag to show the indicator.

Related

Implement Back Pressed In Android Fragments

I've been stuck in a situation and i need some help over here. There are many articles on this topic here but none of them answered my question. I want to implement onBackPressed() in fragments and show dialog box which shows to exit the application or not. Any help would be appreciated.
LoginFragment.java
public class LoginFragment extends Fragment {
public static final String TAG = LoginFragment.class.getSimpleName();
private EditText mEtEmail;
private EditText mEtPassword;
private Button mBtLogin;
private TextView mTvRegister;
private TextView mTvForgotPassword;
private TextInputLayout mTiEmail;
private TextInputLayout mTiPassword;
private ProgressBar mProgressBar;
private CompositeSubscription mSubscriptions;
private SharedPreferences mSharedPreferences;
#NonNull
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_login,container,false);
mSubscriptions = new CompositeSubscription();
initViews(view);
initSharedPreferences();
return view;
}
private void initViews(View v) {
mEtEmail = v.findViewById(R.id.et_email);
mEtPassword = v.findViewById(R.id.et_password);
mBtLogin = v.findViewById(R.id.btn_login);
mTiEmail = v.findViewById(R.id.ti_email);
mTiPassword = v.findViewById(R.id.ti_password);
mProgressBar = v.findViewById(R.id.progress);
mTvRegister = v.findViewById(R.id.tv_register);
mTvForgotPassword = v.findViewById(R.id.tv_forgot_password);
mBtLogin.setOnClickListener(view -> login());
mTvRegister.setOnClickListener(view -> goToRegister());
mTvForgotPassword.setOnClickListener(view -> showDialog());
}
private void initSharedPreferences() {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
}
private void login() {
setError();
String email = mEtEmail.getText().toString();
String password = mEtPassword.getText().toString();
int err = 0;
if (!validateEmail(email)) {
err++;
mTiEmail.setError("Email should be valid !");
}
if (!validateFields(password)) {
err++;
mTiPassword.setError("Password should not be empty !");
}
if (err == 0) {
loginProcess(email,password);
mProgressBar.setVisibility(View.VISIBLE);
} else {
showSnackBarMessage("Enter Valid Details !");
}
}
private void setError() {
mTiEmail.setError(null);
mTiPassword.setError(null);
}
private void loginProcess(String email, String password) {
mSubscriptions.add(NetworkUtil.getRetrofit(email, password).login()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(this::handleResponse,this::handleError));
}
private void handleResponse(Response response) {
mProgressBar.setVisibility(View.GONE);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.TOKEN,response.getToken());
editor.putString(Constants.EMAIL,response.getMessage());
editor.apply();
mEtEmail.setText(null);
mEtPassword.setText(null);
Intent intent = new Intent(getActivity(), HomeActivity.class);
startActivity(intent);
}
private void handleError(Throwable error) {
mProgressBar.setVisibility(View.GONE);
if (error instanceof HttpException) {
Gson gson = new GsonBuilder().create();
try {
String errorBody = ((HttpException) error).response().errorBody().string();
Response response = gson.fromJson(errorBody,Response.class);
showSnackBarMessage(response.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
} else {
showSnackBarMessage("No Internet Connection!");
}
}
private void showSnackBarMessage(String message) {
if (getView() != null) {
Snackbar.make(getView(),message,Snackbar.LENGTH_SHORT).show();
}
}
private void goToRegister(){
FragmentTransaction ft = getFragmentManager().beginTransaction();
RegisterFragment fragment = new RegisterFragment();
ft.replace(R.id.fragmentFrame,fragment,RegisterFragment.TAG);
ft.addToBackStack(null).commit();
}
private void showDialog(){
ResetPasswordDialog fragment = new ResetPasswordDialog();
fragment.show(getFragmentManager(), ResetPasswordDialog.TAG);
}
#Override
public void onDestroy() {
super.onDestroy();
mSubscriptions.unsubscribe();
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements ResetPasswordDialog.Listener {
public static final String TAG = MainActivity.class.getSimpleName();
private LoginFragment mLoginFragment;
private ResetPasswordDialog mResetPasswordDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
loadFragment();
}
}
private void loadFragment() {
if (mLoginFragment == null) {
mLoginFragment = new LoginFragment();
}
getFragmentManager().beginTransaction().replace(R.id.fragmentFrame, mLoginFragment, LoginFragment.TAG).commit();
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String data = intent.getData().getLastPathSegment();
Log.d(TAG, "onNewIntent: " + data);
mResetPasswordDialog = (ResetPasswordDialog) getFragmentManager().findFragmentByTag(ResetPasswordDialog.TAG);
if (mResetPasswordDialog != null)
mResetPasswordDialog.setToken(data);
}
#Override
public void onPasswordReset(String message) {
showSnackBarMessage(message);
}
private void showSnackBarMessage(String message) {
Snackbar.make(findViewById(R.id.activity_main), message, Snackbar.LENGTH_SHORT).show();
}
}
In My Login Fragment, I want to show a dialog box "Do you want to exit the application or not". On Yes it dismiss the current fragment and end the activity otherwise it'll remain active. Help please!
You can even try this way
MainActivity.java
#Override
public void onBackPressed() {
if (getFragmentManager() != null && getFragmentManager().getBackStackEntryCount() >= 1) {
String fragmentTag = getFragmentManager().findFragmentById(R.id.frame_container).getTag();
if(fragmentTag.equals(LoginFragment.getTag())){
// show Dialog code
}else{
super.onBackPressed();
}
} else {
super.onBackPressed();
}
}
Add this code in your main activity so that when login fragment is added and you click backpress, then on first if the fragment is added to fragment transaction, then first it finds the fragment and check if its tag is equals to the login fragment tag. Then if both tag matches, then you can show your exit alert dialog.
Android team has prepared a new way of handling the back button pressed on Fragments for us, so you should check this out. It's called OnBackPressedDispatcher.
You need to register OnBackPressedCallback to the fragment where do you want to intercept back button pressed. You can do it like this inside of the Fragment:
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
//show exit dialog
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}

Alarm keeps playing after onPause called

Here's code for a timer that plays a sound once it reaches 0 (timer works fine). The problem is the sound persists even through onPause() in MainActivity.java called.
I implemented onDestroy() in SimpleIntentService.java to stop the sound, but apparently it's never called even with finish() in the calling Activity. How am I supposed to make the sound stop when the app is paused?
Here's my MainActivity.java
public class MainActivity extends Activity {
private BroadcastReceiver broadcastReceiver;
NumberPicker picker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
picker = (NumberPicker) findViewById(minutePicker);
Log.i("TurnToTech", "Project Name - SimpleBackgroundService");
picker.setMinValue(0);
picker.setMaxValue(20);
broadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context arg0, Intent intent) {
String text = intent.getStringExtra(SimpleIntentService.PARAM_OUT_MSG);
Toast.makeText(getApplicationContext(),
text, Toast.LENGTH_SHORT).show();
}
};
}
Intent msgIntent;
public void startTimer(View view) {
setContentView(R.layout.activity_main);
msgIntent = new Intent(this, SimpleIntentService.class);
msgIntent.putExtra(SimpleIntentService.PARAM_IN_MSG, "Alarm: ");
msgIntent.putExtra("time", picker.getValue());
startService(msgIntent);
}
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(SimpleIntentService.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(broadcastReceiver,filter);
}
public void onPause() {
finish();
unregisterReceiver(broadcastReceiver);
super.onPause();
}
}
And the SimpleIntentService.java
public class SimpleIntentService extends IntentService {
public static final String PARAM_IN_MSG = "in_msg";
public static final String PARAM_OUT_MSG = "out_msg";
int time;
public static final String ACTION_RESP = "org.turntotech.intent.action.MESSAGE_PROCESSED";
public SimpleIntentService() {
super("SimpleIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
System.out.println("SimpleIntentService Called");
String msg = intent.getStringExtra(PARAM_IN_MSG);
int time = intent.getIntExtra("time", 0);
// Timer implementation
if (time == 0 ){
playSound();
}
while(time > 0){
SystemClock.sleep(5000); // 5 seconds
time -= 5;
String resultTxt = msg + time + " seconds remaining";
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(PARAM_OUT_MSG, resultTxt);
broadcastIntent.putExtra("time", time);
sendBroadcast(broadcastIntent);
if (time == 0) {
playSound();
}
}
}
Uri alert;
public void playSound(){
alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), alert);
r.play();
}
public void onDestroy() {
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), alert);
r.stop();
super.onDestroy();
}
}
In your IntentService you're not really stopping the same alarm in your onDestroy function. Because each time you're getting a new instance of it.
So I would like to suggest to keep a public static variable of Ringtone so that it can be accessed from everywhere. Declare them in your MainActivity.
public static Ringtone r;
public static Uri alert;
Initialize them in the onCreate function of your MainActivity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ... Other statements
// Initialize ringtone here
initializeRingtone();
}
private void initializeRingtone() {
alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
r = RingtoneManager.getRingtone(getApplicationContext(), alert);
}
Now the onPause() function of your MainActivity should look like this
public void onPause() {
unregisterReceiver(broadcastReceiver);
r.stop();
super.onPause();
}
And if you want to play the sound after you resume the application from background and then the timer runs out, you might consider doing something like this in the onResume function of your MainActivity
public void onResume() {
super.onResume();
registerReceiver(broadcastReceiver);
initializeRingtone(); // Initialize it again.
}
And the playSound() function in the IntentService might look like this.
public void playSound(){
// Initialize the alert and ringtone again.
MainActivity.alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
MainActivity.r = RingtoneManager.getRingtone(getApplicationContext(), alert);
MainActivity.r.play();
}
public void onDestroy() {
MainActivity.r.stop();
super.onDestroy();
}
Hope that helps!

Call method on Existing Activity from another Activity's fragment

I have a fragment HostEditFragment which is loaded up by activity HostEditActivity. When I finish editing in the fragment I'd like to call a method on MainActivity. I'm trying to do it with an Interface and intent at the moment but it starts a new MainActivity and doesn't seem to work.
Just wondering if there's a better way of doing this.
I think it's creating a new MainActivity rather than using the existing one as SfnViewerFragment is coming back as null. I need it to be the existing MainActivity and SfnViewerFragment.
Here's some skeletal code so you can see what I've tried.
HostEditFragment:
public class HostEditFragment extends Fragment {
OnViewerEditedListener callback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callback = (OnViewerEditedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnViewerEditedListener");
}
}
public void saveHost() {
//...
callback.onViewerEdited(id);
}
public interface OnViewerEditedListener {
public void onViewerEdited(Long id);
}
}
HostEditActivity:
public class HostEditActivity extends ActionBarActivity implements HostEditFragment.OnViewerEditedListener {
public void onViewerEdited(Long id) {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("id", id);
startActivity(intent);
}
}
MainActivity:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri data = getIntent().getData();
Uri viewerUri;
if (data != null) {
//....
} else {
Long id = getIntent().getLongExtra("id", -1);
if (id != -1) {
onViewerEdited(id);
}
}
public void onViewerEdited(Long id) {
SfnViewerFragment sfnViewerFragment = (SfnViewerFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":0");
sfnViewerFragment.recreateWebView(id);
viewPager.setCurrentItem(0, true);
}
}

How can I destroy an Activity from a static method?

I have a subclass checkLoginTask in my Activity LoginActivity (this activity is for the login of a user) . This subclass is called from in the onPostExecute() from a class that extends AsynTask.
I want to destroy the activity LoginActivty if theLoginOk == "ok" and start the activity MainActivity. I used finish() but I got a error Non-Static method "finish()" cannot be referenced from a static context
I tried with final Activity activity = this; but does not worked.
this is the method on my Avtivity LoingPage
public static void checkLoginTrue(JSONObject jsonObject, Context context){
if(jsonObject != null) {
Intent intent = new Intent(context, MainActivity.class);
try {
JSONObject student = jsonObject.getJSONObject("status");
String theId = student.getString("id");
String theLoginOk = student.getString("login");
Log.i("JSON login", theLoginOk);
if (theLoginOk.equals("ok")) {
intent.putExtra("id", theId);
intent.putExtra("login", theLoginOk);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
// something
}
} catch (JSONException e) {
Log.w("error", e.getMessage());
}
}
}
How can I solve this?
here no need for static method. if you want practice for calling static method in activity class, Create onr Util class in that create static methods and call from activity override methods.
like
public class Utill
{
public static void checkLoginTrue(JSONObject jsonObject, Context context, Class<? extends Activity> myClass){
if(jsonObject != null) {
Intent intent = new Intent(context, myClass);
try {
JSONObject student = jsonObject.getJSONObject("status");
String theId = student.getString("id");
String theLoginOk = student.getString("login");
Log.i("JSON login", theLoginOk);
if (theLoginOk.equals("ok")) {
intent.putExtra("id", theId);
intent.putExtra("login", theLoginOk);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
// something
}
} catch (JSONException e) {
Log.w("error", e.getMessage());
}
}
}
}
then call
Utils.checkLoginTrue(jsonObject, this, MainActivity.class);
in your activity any override non-static and/or static method.
Use Broadcast receiver to finish activity or eventbus to avoid leaks in memory, singletons should not exists in android!
Example:
public class FinishableActivity extends AppCompatActivity {
public static final String ACTION_FINISH = FinishableActivity.class.getName() + ".FINISH";
public static final String EXTRA_ACTIVITY_CLASS = "EXTRA_ACTIVITY_CLASS";
private FinishBroadcastListener finishReceiver;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finishReceiver = new FinishBroadcastListener()
.register(this);
}
#Override
protected void onDestroy() {
finishReceiver.unregister(this);
finishReceiver = null;
super.onDestroy();
}
public static void show(Context context, Class<? extends Activity> cls) {
context.startActivity(new Intent(context, cls) {{
addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REORDER_TO_FRONT | FLAG_ACTIVITY_BROUGHT_TO_FRONT);
}});
}
public static void hide(Context context, Class<? extends Activity> cls) {
context.sendBroadcast(new Intent(ACTION_FINISH) {{
putExtra(EXTRA_ACTIVITY_CLASS, cls);
}});
}
class FinishBroadcastListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = (intent == null) ? "" : intent.getAction();
action = (action == null) ? "" : action;
if (ACTION_FINISH.contentEquals(action)) {
onFinishCalled((Class<? extends Activity>) intent.getSerializableExtra(EXTRA_ACTIVITY_CLASS));
}
}
public FinishBroadcastListener register(Context context) {
context.registerReceiver(this, new IntentFilter(ACTION_FINISH));
return this;
}
public void unregister(Context context) {
context.unregisterReceiver(this);
}
}
private void onFinishCalled(Class<? extends Activity> cls) {
if (cls == null) {
return;
} else {
if (cls.equals(getClass())) {
finish();
}
}
}
}
Your finish() didn't work when you tried because you need an actual activity object to call it on. Static methods do not run on objects. Thats why they can't use this.
You must pass your activity object reference to the static method and then finish() it. If you have already passed it as Context context then cast it to activity first. Example:
//if your context is actually activity reference, use line below
//if not, add another Activity argument to the method
//if you cant get to the activity to pass it as argument, save it in a static reference somewhere, during ocCreate for example, and you can access it globally
Activity activity = (Activity) context;
//correct way to use finish()
activity.finish();

ringtone manager is not stop ringtone android

i have two class incomingCallRing.java and IncomingCallSlider.java
one class show the UI and 2nd class define the functions.
The problem i m facing is when i click on reject call button the music of incoming call wont stop.Here is the code of both classes.
incomingCallSlider.java
private void RejectCall()
{
m_objBtnRejectCall = (Button) m_objActiveActivity.findViewById(R.id.RejectCallButton);
m_objBtnRejectCall.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
//Log.e("Reject Call", m_sIncomingCallId);
VaxPhone.m_objVaxVoIP.RejectCall(m_sIncomingCallId);
HideSlider();
if(IncommingCall != null)
IncommingCall.cancel(0);
} }); }
IncomingCallRing.java
public static IncommingCallRing m_objIncommingCallRing;
Ringtone m_objRingtone;
Activity m_objActiveActivity;
public IncommingCallRing()
{
m_objIncommingCallRing = this;
}
public void SetActiveActivity(Activity ReferenceActivity)
{
m_objActiveActivity = ReferenceActivity;
}
private void StartRingtone()
{
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
m_objRingtone = RingtoneManager.getRingtone(m_objActiveActivity.getApplicationContext(), notification);
m_objRingtone.play();
}
private void StopRingtone()
{
if(m_objRingtone == null)
return;
if(m_objRingtone.isPlaying())
m_objRingtone.stop();
}

Categories