Intent intent=new Intent(MainActivity.this, ContactListActivity.class);
startActivity(intent);
MainActivity.this is written in java and ContactListActivity is written in kotlin. I am trying to call the ContactListActivty but end up getting the error
have you declared this activity in your AndroidManifest.xml?
I have also added the activity in the manifest file.
<activity android:name="Chat_Activity$Connections$ContactListActivity"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>
EDIT:
ContactListActivity.kt
class ContactListActivity : AppCompatActivity() {
private var mBroadcastReceiver: BroadcastReceiver? = null
private val TAG:String="ContactListActivity"
//static variable
object Obz{
#JvmStatic val GetContactListFromServer:String="Contact List"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(layout.activity_contact_list)
title = "Contact list"
contact_list.hasFixedSize()
contact_list.layoutManager= LinearLayoutManager(this)
getContactListAndNextActivity()
}
fun getContactListAndNextActivity(){
contact_list.adapter= ContactListAdaptor(applicationContext, dbHelper(applicationContext).getContactList())
}
}
Your manifest name entry looks suspect.
android:name="Chat_Activity$Connections$ContactListActivity"
I'm not sure what the fully qualified path name is, but try:
android:name=".ContactListActivity"
or
android:name="<qualified.path.to>.ContactListActivity"
I had similar problem, Try to rename Your activity add 1 symbol for ex: and inside your manifest
write
android:name=".ContactListActivity1"
after that you can rename again and set it old name
Related
Hello so I have the problem that I registered a onSharedPreferenceChangeListener in my MainActivity. The only preference I have is a ListPreference with 3 different options. So at the start of the program it still gets triggered the first - 3 times mostly, sometimes it doesn't even trigger at the beginning. I don't think that's how it is supposed to work so my code is down below if more is needed just write a comment of a specific part.
// (from MainActivity)
this.sharedPreferences.registerOnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, s: String ->
var value = sharedPreferences.getString("location", "")
controller.setLocation(value, this)
}
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
}
Found the solution by myself, for everyone who is having an issue like that. It's probably the scope. The listener gets lost when you are switching between activities.
How to fix: put the listener block as a global variable and just register it in your "onCreate" method.
I have an activity which has a NavHostFragment. The activity receives certain values in its intent. I want to pass this data to the first fragment i.e startDestination of the navigation graph. I couldn't find any documentation regarding this.
I have already gone through this question on SO but I can't seem to find the addDefaultArguments method for navController.getGraph().
Is it possible to pass bundle to startDestination?
Answering my own question as I found the correct approach in the updated Navigation documentation.
At the time of writing this answer, I am using Navigation 2.2.0-alpha01
If you want to pass some data to the start destination directly as arguments from host activity, you need to manually set your host’s navigation graph inside the host activity’s onCreate() method, as shown below:
Get you navController:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
Then in the host activity's onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
Or if you want to pass the whole intent extras as it is to the startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
Since intent.extras would return a Bundle only
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in
the NavHostFragment definition, because doing so results in inflating
and setting the navigation graph twice.
While reading these arguments in your startDestination fragment:
If you are using the Safe Args Plugin (which is very much recommended), then in your fragment:
private val args by navArgs<DummyFragmentArgs>()
Safe Args plugin would generate an Args class by appending Args to your fragment name. For example, if you fragment is called DummyFragment then Safe Args would generate a class called DummyFragmentArgs
where navArgs<> is an extension function defined in Android KTX
If you are not using Android KTX, you can get the args object like:
val args = DummyFragmentArgs.fromBundle(arguments!!)
Once you've acquired the arguments object, you can simply fetch your arguments:
args.someArgument
Notice how we passed "some_argument" as argument, and we are reading it as someArgument using Safe Args
If you are not using Safe Args (there is no reason to not use it though), you can access your arguments like this:
arguments?.getString("some_argument")
All of this is documented in Migrate to Navigation Component documentation here:
https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment
I found the solution after some research. It works with the latest Navigation library release. Refer the below code:
Add this in your activity layout. Note: We are not setting app:navGraph argument in the xml file. We will set it dynamically.
<fragment
android:id="#+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true" />
In your activity java file, write the below code and make changes accordingly. Use NavArgument to pass your argument value and add the argument to your custom Navgraph and then set graph.
public class YourActivity extends AppCompatActivity {
private NavArgument nameArg, mailArg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);
nameArg = new NavArgument.Builder().setDefaultValue("your name").build();
mailArg = new NavArgument.Builder().setDefaultValue("your email id").build();
NavController navController = Navigation.findNavController(this, R.id.fragment);
NavInflater navInflater = navController.getNavInflater();
NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph);
navGraph.addArgument("your name key", nameArg);
navGraph.addArgument("your mail key", mailArg);
navController.setGraph(navGraph);
}
}
Write the navigation graph below and add the same argument keys to the starting fragment.
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph"
app:startDestination="#+id/profile_basic">
<fragment
android:id="#+id/profile_basic"
android:name="com.yourpackage.ProfileBasicFragment"
android:label="Profile Basic"
tools:layout="#layout/fragment_profile_basic">
<argument android:name="your name key"
app:argType="string"/>
<argument android:name="your mail key"
app:argType="string"/>
</fragment>
</navigation>
In your fragment, just fetch the values using getArguments() function.
String name = getArguments().getString("your name key");
String mail = getArguments().getString("your mail key");
i also came across same issue,
This is how i resolved it:
Remove the the xml setup of NavHostFragment from your_activity.xml : i.e remove app:navGraph="#navigation/nav_graph
This is how your XML Should look like.
<fragment
android:id="#+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
/>
Add Setup for NavHostFragment Programatically in onCreate() of activity.
And pass bundle data using NavGraph.addDefaultArguments(bundleData) api
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.editor_layout)
setupNavigation()
}
private fun setupNavigation() {
val navHostFragment = nav_host as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.nav_graph)
graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination
navHostFragment.navController.graph = graph
}
UPDATE:
Dependencies in my Project Gradle file:
dependencies {
def nav_version = "1.0.0-alpha08"
implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin}
}
NOTE: In Navigation Component version 1.0.0-alpha09 for some reason google have no method as addDefaultArguments() might be fixed soon. But lower version's have addDefaultArguments() method.I have checked both in java and kotlin so try using 1.0.0-alpha07 or 1.0.0-alpha08
I checked the source code an saw that there a lot of changes regarding navigation destination and arguments.
I think the proper way to pass arguments to start destination is using 'addArgument' method, something like this:
val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)
Maybe there is a better way, but i didn't found one.
Though it is a late answer there is a very easy way for passing bundles using navigation controller/Navigation Architecture:
Fragment that will send data
//Best to put in onViewCreated
val navController = findNavController()
//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")
navController.navigate(R.id.action_signupFragment_to_signinFragment,b)
Fragment that will receive data
val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:""
Depending on the type of data you are sending you need to update the safe call or make the variables nullable.
I cannot find this method, too. It is not existant in the architecture components documentation.
But the is another way to set arguments to the start destination:
// Kotlin Code, in Fragment
with(findNavController().graph) {
get(startDestination).addArgument(...)
}
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = container as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.main_nav)
var data : Data = intent.getParcelableExtra("DATA") as Data
var bundle : Bundle = Bundle()
bundle.putParcelable("DATA", data)
graph.addDefaultArguments(bundle)
graph.addDefaultArguments(intent!!.extras!!)
navHostFragment.navController.graph = graph
}
}
Add the above code in Activity for sending the data using using navigation
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking
}
Add the above code in fragment side
you can add arguments in your graph like this
<fragment
android:id="#+id/exampleFragment"
android:label="example_fragment"
android:name="com.example.yourapp.ui.ExampleFragment"
tools:layout="#layout/example_fragment">
<argument
android:name="exampleArgs"
app:argType="reference"
android:defaultValue="#string/example"/>
</fragment>
https://developer.android.com/guide/navigation/navigation-pass-data
Navigation 1.0.0
val navHostFragment = root_nav_host_fragment as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.navigation)
val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
val bundle = bundleOf(KEY_SECTION_ID to sectionId)
navHostFragment.navController.setGraph(graph, bundle)
I have a main service which should always be running in the background in my Android application for handling a bluetooth device connection and feeding data to it.
According to these questions, it is a normal behavior if my service live in my app process to get killed when app closes,
Android Background Service is restarting when application is killed
Service restarted on Application Close - START_STICKY
keeping background service alive after user exit app
But I even tried running my service in a separate process using this tag android:process=":service" inside my manifest but it also get killed and restarted when my app get killed!
More info:
I start my service in my application onCreate method, and for binding to my service in my activity I use BIND_AUTO_CREATE, which generally I am not sure is it correct or not.
update:
I also have another service which bind inside my current service, I am not sure if it might be source of issue!
more update:
I am using dagger for DI, is it possible by mistake I am using application context for creating some objects inside my service!! could this be the cause of this issue?
some more update
I separate dagger components for my service and now application and service got no common objects, but problem still remains.
update with a sample code which got the same issue
Here is the Application class:
class MyApplication:Application() {
override fun onCreate() {
super.onCreate()
startService(Intent(this, MyService::class.java))
}
}
Here is the Service class:
class MyService : Service() {
private val mBinder = MyBinder()
inner class MyBinder : Binder() {
internal val service: MyService
get() = this#MyService
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i(TAG, "onStartCommand")
return START_STICKY
}
override fun onCreate() {
super.onCreate()
Log.i(TAG, "onCreate")
}
override fun onBind(intent: Intent): IBinder? {
Log.i(TAG, "onBind")
return mBinder
}
override fun onUnbind(intent: Intent): Boolean {
Log.i(TAG, "onUnbind")
return super.onUnbind(intent)
}
override fun onDestroy() {
Log.i(TAG, "onDestroy")
super.onDestroy()
}
companion object {
val TAG = "MyService"
}
}
This is the Activity:
class MainActivity : AppCompatActivity() {
lateinit var context: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i(TAG, "onCreate")
context = this
}
//connect to the service
val myServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.i(TAG, "onServiceConnected")
val binder = service as? MyService.MyBinder
// ...
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.i(TAG, "onServiceDisconnected")
}
}
override fun onResume() {
super.onResume()
Log.i(TAG, "onResume")
val intent = Intent(context, MyService::class.java)
bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
}
override fun onPause() {
super.onPause()
Log.i(TAG, "onPause")
unbindService(myServiceConnection)
}
companion object {
val TAG = "MainActivity"
}
}
Last but not least, the Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mirhoseini.stickyservice">
<application
android:name=".MyApplication"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:process=":service" />
</application>
</manifest>
It is a normal behavior for a service to stop when the application main thread stops.
Personally, I don't agree with using an internal service in a separate process for the regular development and functionality sharing between modules. A worker or IntentService is the more appropriate candidate most of the times.
To keep your service alive after user exits the app, try one of the scheduled threading mechanism that suits your needs, best :
1- TimerTask ( not really recommended !)
2- Executors.newScheduledThreadExecutor
3- AlarmManager
4- JobScheduler
I was trying Kotlin in my Android project. There is a broadcast receiver for network change events in my activity. Code is as below:
BaseActivity.kt
abstract class BaseActivity : AppCompatActivity() {
private val networkChangeReceiver = NetworkChangeReceiver()
override fun onStart() {
super.onStart()
registerReceiver(
receiver = networkChangeReceiver,
intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
}
override fun onStop() {
super.onStop()
unregisterReceiver(receiver = networkChangeReceiver)
}
}
NetworkChangeReceiver.kt
class NetworkChangeReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.e("network changed")
}
}
I don't see any problem in it. But my kotlin plugin shows me following error:
None of following functions can be called with arguments supplied
The arguments supplied for first one is correct ASAFIK. I am not an expert in Kotlin, just learning it for fun. Is this intended behaviour of Kotlin, error in plugin or am I missing something? Can anyone explain?
First the parameter is named filter and not intentFilter and if you correct this, you get another error. Which says: "Named arguments are not allowed for non-Kotlin functions" Reason for this is that the method public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) is from Android and written in java. Removing the names should work fine:
registerReceiver(
networkChangeReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
Problem is a bit complex ,First of all both activity A and activity B activity B have android:noHistory = true in manifest. i have a custom serializable class suppose MyClass , that custom class is actually storing the context of the Activity B through constructor. And i have an object name obj in Activity B of type MyClass , Now i want to transfer this object to Activity C through intent when back button is pressed in Activity B.
From Activity A there is a button that open activity B without an issue, issue starts when i try to open activity C through B in onBackPressed(), with transferring serializable object . i am receiving NULL in Activity C.
[Updated] MyClass:
#SuppressWarnings("serial")
public class MyClass implements Serializable{
private final String SHAREDKEY_HIGHSCORE = "High Scores";
private final String FIELDKEY_HIGHSCORE = "HighScore";
private final String FIELDKEY_HIGHTIME = "HighTime";
private SharedPreferences sp;
private SharedPreferences.Editor spEditor;
public MyClass(Context context) {
resetScore();
sp = context.getSharedPreferences(SHAREDKEY_HIGHSCORE, Context.MODE_PRIVATE);
spEditor = sp.edit();
}
public void resetScore(){
newTime = 0;
newScore = 0;
highTime = 0;
highScore = 0;
}
}
Activity B:
public class ActivityB extends Activity {
MyClass scores;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
scores = new MyClass(this);
}
#Override
public void onBackPressed() {
Intent intent = new Intent(this, ActivityC.class);
in.putExtra("Scores", scores);
startActivity(intent);
}
}
Activity C:
public class ActivityC extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
MyClass score = (MyClass) getIntent().getSerializableExtra("Scores");
//score is null here always
}
}
Manifest:
<activity
android:name=".ActivityA"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ActivityB"
android:noHistory="true">
</activity>
<activity android:name=".ActivityC">
How can receive my custom class in activity C successfully ? please help
the problem is clearly here // i have to store context of Activity B no matter what.
NO! You do not have to store context of Activity B. You're trying to do it, for the wrong reasons.
In Android you must never try to keep an activity for longer than its lifecycle, and you should never try to Serialize a Context. It just doesn't work like this and that's the reason it will not work.
I'm putting this as an answer (instead of a comment) because that's what is is.
The solution to your problem is: re-think the architecture of your app. There're several different correct ways to passing or sharing information through activities, but trying to hold to a context and serialize it, is not one of them.
According to the Android documentation, when you declare an Activity with noHistory, it will not stay in the Activities Stack.
Your problem is happening after your onBackPressed finishes. Your Activity B context is cleaned by the Android OS GC, so when Activity C is created the pointer you had to that context is pointing to a null location.
I suggest using another architecture to pass information between your activities. Try searching for "Android extending Application class" in google :)
I don't know what you're trying to achieve , but storing some Activity's Context is not gonna get you there. As #Budius stated , you should rethink what you're trying to do. The docs say about Context:
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.
I don't see any reasons why one would need to keep and serialize it . Even if you need a "global" context , you can always call getApplication() inside your Activity.