I'm trying to finish an activity from another (android) with kotlin. I know the wat to do it with java is with the following code (https://stackoverflow.com/a/10379275/7280257)
at the first activity:
BroadcastReceiver broadcast_reciever = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent intent) {
String action = intent.getAction();
if (action.equals("finish_activity")) {
finish();
// DO WHATEVER YOU WANT.
}
}
};
registerReceiver(broadcast_reciever, new IntentFilter("finish_activity"));
On the other activity:
Intent intent = new Intent("finish_activity");
sendBroadcast(intent);
For some reason converting the java activity to kotlin doesn't give a valid output, if someone could give me the correct syntax to do it properly with kotlin I will appreciate it
kotlin output (first activity) [OK]:
val broadcast_reciever = object : BroadcastReceiver() {
override fun onReceive(arg0: Context, intent: Intent) {
val action = intent.action
if (action == "finish_activity") {
finish()
// DO WHATEVER YOU WANT.
}
}
}
registerReceiver(broadcast_reciever, IntentFilter("finish_activity"))
kotlin output (2nd activity) [OK]
val intent = Intent("finish_activity")
sendBroadcast(intent)
ERROR: http://i.imgur.com/qaQ2YHv.png
FIX: THE CODE SHOWN IS RIGHT, YOU JUST NEED TO PLACE IT INSIDE THE onCreate FUNCTION
Simple code to finish a particular activity from another:
class SplashActivity : AppCompatActivity(), NavigationListner {
class MyClass{
companion object{
var activity: Activity? = null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MyClass.activity = this#SplashActivity
}
override fun navigateFromScreen() {
val intent = Intent(this,LoginActivity::class.java)
startActivity(intent)
}
}
Now call SplashActivity.MyClass.activity?.finish() from another activity to finish above activity.
The error Expecting member declaration is there because you wrote a statement (the function call) inside a class. In that scope, declarations (functions, inner classes) are expected.
You have to place your statements inside functions (and then call those from somewhere) in order for them to be executed.
Related
I am working on an expense tracker app. When I click on item in recycleview, it takes me to another activity where I have two buttons : update and delete. The issue is I don't get the idea how to delete item from recycleview, which is in another activity, when delete button in that activity is pressed. Actually, I also searched and looked up other similar questions and answers on stack overflow however that didn't help me. If someone can help me on this, I will appreciate it greatly.
This is my code where I am passing the position of my item :
final int pos = holder.getAdapterPosition();
holder.date.setText(MyModel.getDate());
holder.note.setText(MyModel.getNote());
holder.Btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(context,Update_transaction.class);
i.putExtra("key",myViewsList.get(pos).getId());
i.putExtra("pos",holder.getAdapterPosition());
context.startActivity(i);
}
});
This is the code where I am retrieving the data in another activity :
Bundle bundle = getIntent().getExtras();
Update_db = new DataSaver(this);
if(bundle != null)
{
id = bundle.getString("key");
pos = bundle.getString("pos");
Toast.makeText(this, "pos : " + pos, Toast.LENGTH_SHORT).show();
}
For interaction between activities, you can use the LocalBroadcastManager. You can send a broadcast from one activity and receive it in another.
Send broadcast
val intent = Intent("ACTION")
intent.putExtra("needUpdate", true)
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent)
Receive broadcast
1.Create a listener
val myBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
println("Your value: " + intent?.getStringExtra("needUpdate"))
}
}
Register
override fun onResume() {
// …
val filter = IntentFilter("ACTION")
LocalBroadcastManager.getInstance(applicationContext).registerReceiver(myBroadcastReceiver, filter)
}
Cancel registration
override fun onPause() {
// …
LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(myBroadcastReceiver)
}
More details: https://developer.android.com/guide/components/broadcasts
I have hideKeyboard(view: View) method in util class. In my activity I want to call that method. I created object in activity utils = Utils() and then utils.HideKeyboard(binding.authConstraint) but when Im trying to click on constraintLayout it is throwing error "System services not available to Activities before onCreate()" what am I doing wrong ?
my Util Class
open class Utils():Activity(){
fun hideKeyboard(view: View) {
val inputMethodManager =
getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
my activity
class AuthActivity : ActivityWithDisposableList() {
private lateinit var binding: ActivityAuthBinding
private lateinit var authViewModel: AuthViewModel
val utils = Utils()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_auth)
authViewModel = ViewModelProviders.of(this).get(AuthViewModel::class.java)
binding.authViewModel = authViewModel
binding.lifecycleOwner = this
authViewModel.isKeyboardClosed.observe(this, Observer { isTrue ->
if (isTrue) {
utils.hideKeyboard(binding.authConstraint,this)
binding.usernameInputEditText.clearFocus()
binding.passwordInputEditText.clearFocus()
}
})
}
}
Do not create an instance of an Activity subclass yourself. And do not make some arbitrary class extend Activity, just because you need a Context. Get the Context from a parameter to a constructor or function.
With that in mind, replace your Utils with:
class Utils {
fun hideKeyboard(view: View) {
val inputMethodManager =
view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
Here, you are getting the Context from the View that you are supplying.
Note that you could also go with object Utils or have hideKeyboard() be an extension function on View, if you liked.
I'm trying to make something like a timed session when a user logs in in the app. I want to set up a timer which, when finished, change the activity with an intent, going back to the login page. I'm new to Android programming and I don't know how something like this should be implemented.
What I tried so far (and currently is working as intended, I just don't know if it's the correct thing to do, because it seems odd to have a function from another activity running in the background like this) is:
Countdowntimer is setted up in the login activity.
When the "login" button is pressed the timer starts.
OnTick() changes the activity with an intent.
OnFinish() is setted up in the login activity and, when it runs, it changes activity with an intent going back to the login page, even if the user is on a completely different activity.
As I said before, this works just fine, it just seems strange and I can't find anything that tells how this should work.
Using Intent Service Start your Timer & Add Event Bus Dependency to your project.
Event Bus
public class TimerIntentService extends IntentService {
public TimerIntentService() {
super("TimerIntentService");
}
public static void startTimer(Context context) {
Intent intent = new Intent(context, TimerIntentService.class);
context.startService(intent);
}
private CountDownTimer countdownTimer = new CountDownTimer(60000,1000) {
#Override
public void onTick(long millisUntilFinished) {
EventBus.getDefault().postSticky(new MessageEventToActivityEvent(TimerStatus.RUNNING));
}
#Override
public void onFinish() {
EventBus.getDefault().postSticky(new MessageEventToActivityEvent(TimerStatus.FINISHED));
}
};
#Override
protected void onHandleIntent(Intent intent) {
EventBus.getDefault().postSticky(new MessageEventToActivityEvent(TimerStatus.STARTED));
countdownTimer.start();
}
#Override
public void onDestroy() {
super.onDestroy();
try{
countdownTimer.cancel();
} catch (Exception e){
e.printStackTrace();
}
stopSelf();
}}
step 2:
in your first activity start intent service
TimerIntentService.startTimer(context);
step 3:
in your base activity or second activity add like the following
public class TimerBaseActivity extends AppCompatActivity {
#Subscribe(threadMode = ThreadMode.MAIN,sticky=true)
public void onMessageEvent(MessageEventToActivity event) {
if(event.timerStatus!=null){
if(event.timerStatus==TimerStatus.FINISHED){
// do your Stuff
}
if(event.timerStatus.equals(TimerStatus.RUNNING)){
Log.e("Timer State : ",""+event.timerStatus.name());
}
}
}
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}}
With Koin DI & MVVM It is a very simple one.
Step 1: define your timer in your ViewModel
class TimerViewModel(application: Application) : AndroidViewModel(application) {
val isFinished = MutableLiveData<Boolean>().apply { value = false }
val timerTask: CountDownTimer = object : CountDownTimer(60000, 1000) {
override fun onFinish() {
Log.e("CountDownTimer","onFinish")
isFinished.postValue(true)
}
override fun onTick(millisUntilFinished: Long) {
Log.e("millisUntilFinished","$millisUntilFinished")
}
}}
step 2: Add your model as a singleton using Koin
val myModule = module {
single { TimerViewModel(androidApplication()) }}
Step 3: start your time in Your first activity
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
val timerViewModel: TimerViewModel by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
activityMainBinding.viewModel = timerViewModel
activityMainBinding.lifecycleOwner = this
timerViewModel.timerTask.start()
startActivity(Intent(this, SecondActivity::class.java))
}
Step 4: Observe ViewModeldata in Second Activity
class SecondActivity : AppCompatActivity() {
val timerViewModel: TimerViewModel by inject()
lateinit var activitySecondBinding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activitySecondBinding = DataBindingUtil.setContentView(this, R.layout.activity_second)
activitySecondBinding.viewModel = timerViewModel
activitySecondBinding.lifecycleOwner = this
timerViewModel.isFinished.observe(this, Observer {isTimerFinished->
if(isTimerFinished){
Toast.makeText(this#SecondActivity,"Timer Finished",Toast.LENGTH_LONG).show()
}
})
}
fun stopTimer(view:View){
timerViewModel.timerTask.cancel()
}
}
Note:
Problem Solved. This is one of the ways. If you don't want to use singleton object, then run your timer in IntentService. onFinish notify to the activity using EventBus. Event Bus will share your event with multiple activities.
I want to start an activity but strange enough I couldn't find a single place that tells where exactly should I do that.
Here is my code:
#Override public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
Intent service = new Intent(getApplicationContext(), MyTaskService.class); Bundle bundle = new Bundle();
bundle.putString("foo", "bar"); service.putExtras(bundle);
getApplicationContext().startService(service);
}
You can use Android Lifecycle component to detect if app is going to background.
Please refer the below code :
import android.app.Application
import android.arch.lifecycle.ProcessLifecycleOwner
class SampleApp : Application() {
private val lifecycleListener: SampleLifecycleListener by lazy {
SampleLifecycleListener()
}
override fun onCreate() {
super.onCreate()
setupLifecycleListener()
}
private fun setupLifecycleListener() {
ProcessLifecycleOwner.get().lifecycle
.addObserver(lifecycleListener)
}
}
SampleApp is just an Android Application, declared in the manifest like:
<application
android:name=".SampleApp"/>
Code for lifecycleListner :
class SampleLifecycleListener : LifecycleObserver {
#Inject
var component: MyLifecycleInterestedComponent
#OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
component.appReturnedFromBackground = true
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
}
}
In onMoveToBackground() method you can write your code.
For more information refer to this link.
I'm a new to java and android. I was working on my own app but I'm having a problem in passing a method from Activity A to Activity B.
Here is what I did :
ActivityA has Demo() method.
public class ActivityA extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
protected void demo() {
// Do something
}
}
I created the below class to access the method of ActivityA to ActivityB:
public class External {
private ActivityA activitya;
private static External instance = null;
public External(ActivityA activitya) {
this.activitya = activitya;
}
static public External getInstance(ActivityA activitya) {
if (instance == null) {
instance = new MyntraExternal(activitya);
return instance;
} else {
return instance;
}
}
}
Now how can I proceed further? I'm having lots of problem in getting the method which is in ActivityA from ActivityB.
Please anybody help.
Edit :
ActivityB is my launcher class and I want some access from ActivityA's method in ActivityB. What to do ?
Since you are new to Android, I will tell you it's a bad practice call methods from Activity A to B or vice versa, you can pass parameters from one activity to another using intents and bundles and if you need to pass parameters from the second activity to the first you need to use the override method onActivityResults
Here are some usefull link about passing parameters from one activity to another:
https://www.dev2qa.com/passing-data-between-activities-android-tutorial/
In this link you can see a example of how things work.
Hope it helps.
--EDIT (if you need to call a function from B to A in case you want to change something in A upon creation this is the best and simplest way to do it):
In Activity B:
Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("Work","doJump");
startActivity(intent);
In Activity A:
onCreate:
String extra = getIntent().getStringExtra("Work");
if(extra != null && extra.equals("doJump")){
jump();
}
make that method public and static and then access it using class name. e.g. In your 2nd activity, use ActivityB.demo()
Try using startActivityForResult
To start activity B from activity A
startActivityForResult(intent, SOME_CODE)
And to be called back on result you will need to add the following code the also in activity A
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(code){
SOME_CODE -> if (resultCode == Activity.RESULT_OK) doSomething()
}
}
To tell Activity A to call the method, in activity B you can say:
setResult(Activity.RESULT_OK)
finish()
After B is finished, onActivityResult in A will be executed
To go back to A without executing the "doSomething()" method,
setResult(Activity.RESULT_CANCELED)
finish()
Please try this way
public class ActivityA extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void demo() {
// Do something
}
}
public class ActivityB extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityA activityA = new ActivityA(); // create object
activityA.demo(); //
}
}