Why Fragment cannot be public static class? - java

I came across such problem: I wanted to have some Fragment as public static member of my Activity class.
But when I put such Fragment to layout file I receive such exception:
Caused by: android.support.v4.app.Fragment$InstantiationException:
Unable to instantiate fragment com.tst.MainActivity.InnerFragment:
make sure class name exists, is public,
and has an empty constructor that is public
...
My code looks like this:
package com.tst;
public final class MainActivity extends SherlockFragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public static class InnerFragment extends SherlockFragment {
public InnerFragment() {
super();
}
...
}
}
Layout file looks like this:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<fragment
android:id="#+id/inner_fragment"
android:name="com.tst.MainActivity.InnerFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Now my question is why such code throws this Exception? As Android should be able to instanitate InnerFragment as it is public static. What is more I used to use public static Fragments and they worked, but on that time I added them programmatically in code not in xml definition.
Regards,
Michal

Change
android:name="com.tst.MainActivity.InnerFragment"
to
android:class="com.tst.MainActivity$InnerFragment"

Related

Class not found when unmarshalling in PreferenceFragment

I try to implement a day/night system changeable directly from the settings. I used PreferenceFragmentCompat for this but however, when I press the switch preference to change the mode. I have the following error:
E/Parcel: Class not found when unmarshalling: androidx.fragment.app.FragmentManagerState
java.lang.ClassNotFoundException: androidx.fragment.app.FragmentManagerState
Caused by: java.lang.ClassNotFoundException: androidx.fragment.app.FragmentManagerState
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
I looked everywhere but I don't really understand where the error comes from..
This is my Preference Activity:
public class PreferencesActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
if (savedInstanceState == null)
getSupportFragmentManager().beginTransaction().replace(R.id.preferences_container, new PreferencesFragment()).commit();
}
#Override
protected void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.contains(getString(R.string.KEY_PREF_NIGHT_MODE)))
AppCompatDelegate.setDefaultNightMode(sharedPreferences.getBoolean(key, false)? AppCompatDelegate.MODE_NIGHT_YES: AppCompatDelegate.MODE_NIGHT_NO);
}
public static class PreferencesFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}
}
And I use this layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/noteRecyclerBackground"
tools:context=".PreferencesActivity">
<FrameLayout
android:id="#+id/preferences_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</LinearLayout>
There is no crash but an error and this is when the activity restart with AppCompatDelegate.setDefaultNightMode(sharedPreferences.getBoolean(key, false)? AppCompatDelegate.MODE_NIGHT_YES: AppCompatDelegate.MODE_NIGHT_NO);
Well, per the documentation, this sounds like expected behavior.
If this method is called after any host components with attached AppCompatDelegates have been 'created', a uiMode configuration change will occur in each. This may result in those components being recreated, depending on their manifest configuration.

Databinding Event listener

I am trying to set an event listener to an ImageButton but I keep getting this error.
Error:(48, 36) Could not resolve handler::onSelectPictureClicked as a listener.
Here is what my layout looks like.
<data>
<variable
name="handler"
type="CompleteProfileActivityHandler"/>
</data>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_badge_upload"
android:background="#null"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="#string/select_picture"
android:id="#+id/complete_profile_picture_select"
android:onClick="#{handler::onSelectPictureClicked}"/>
And here's my handler class
public class CompleteProfileActivityHandler{
public void onSelectPictureClicked(View view){
choosePicture();
}
}
Thanks in advance. ;)
So I finally figured out what the problem was.
I did not bind the handler to the view in the Activity.
Here's how I did it:
binding.setHandler(new CompleteProfileActivityHandler());
I think your listenr class must implements View.OnClickListener class
public class CompleteProfileActivityHandler implements View.OnClickListener{
public void onSelectPictureClicked(View view){
choosePicture();
}
}
you have to wrate your code on the callback method of this interface.

Set tag abbreviations for custom views on XML

In my app I extend LinearLayout and RelativeLayout, so every time I need to declare a layout in XML (which you may know it's quite often) I need to write a long tag, in order to point to the view's package.
So the XML files look like this:
<com.company.material.widget.LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.company.material.widget.RelativeLayout
android:layout_width="match_parent"
android:layout_height="#dimen/titlebar_height"
android:background="#color/primary"
android:orientation="horizontal">
<TextView
style="#style/Text.Field.Small"
android:id="#+id/form_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<Button
style="#style/Button.Main"
android:id="#+id/form_submit"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
</com.company.material.widget.RelativeLayout>
<com.company.essentials.view.FormView
android:id="#+id/formview"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
This is chaotic!
Is there any way to abbreviate this? Like AppLinearLayout instead of com.company.material.widget.LinearLayout?
Thanks in advance!
You could move your View class to the android.view package. This would allow you to just write <AppRelativeLayout /> instead of <com.company.material.widget.AppRelativeLayout />, since View tag names without package prefixes are 'auto-completed' to the android.view package.
If you don't want to move your whole class to this package, you may just create a dummy sub-class Ă  la:
package android.view;
public class AppRelativeLayout extends com.company.material.widget.RelativeLayout {
// same constructors as super class
public AppRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
You just have to make sure you don't use the same class names as the Android framework already does, such as RelativeLayout, since that would clash with the existing views and layout names. That's why I named the example above AppRelativeLayout.
If it's worth it to you, you can customize your activity's layout inflater.
public class MyActivity extends Activity implements LayoutInflater.Factory {
#Override public void onCreate(Bundle _icicle) {
super.onCreate(_icicle);
setContentView(R.layout.my_activity);
}
#Override public Object getSystemService(String _name) {
Object service = super.getSystemService(_name);
if(LAYOUT_INFLATER_SERVICE.equals(_name)) {
LayoutInflater myInflater = ((LayoutInflater)service).cloneInContext(this);
myInflater.setFactory(this);
return myInflater;
}
return service;
}
#Override public View onCreateView (String _tag, Context _ctx, AttributeSet _as) {
if("mytag".equals(_tag))
return new MyLinearLayout(_ctx, _as);
else
return null;
}
}
setContentView will call getSystemService to obtain a layout inflater, and for each tag that layout inflater will query each of its factories (including our custom one) to see if the factory knows how to create the object that corresponds to that tag.
There is alternative option as well if you like you can do it like this
<view
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.company.material.widget.LinearLayout"
android:orientation="vertical">

Android Change text in TextView

I'm trying to change the text in my TextView by using the setText().
When I try to do this I get the following error:
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{<bla bla bla>}: java.lang.NullPointerException
Caused by: java.lang.NullPointerException
at com.training.mytraining.test.MainActivity.display(MainActivity.java:35)
MainActivity.java
public class MainActivity extends AppCompatActivity {
TextView tvCountry;
private Server theServer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvCountry = (TextView) findViewById(R.id.countryTextView);
theServer = new Server(this);
theServer.weatherFromYahoo();
}
public void display() {
tvCountry.setText("USA");
}
}
Server.java
public class Server extends AppCompatActivity {
MainActivity theMainActivity;
//Constructor
public Server (Context context){
this.theMainActivity = new MainActivity();
}
public void weatherFromYahoo() {
theMainActivity.display();
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:id="#+id/countryTextView"
android:text="#string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
This is just an example of my real code. I did'nt want to put all the code, so I made a new code with just that problem I get. I have to set the text by calling my MainActivity from an another class.
Please help me, I have been stuck here for hours.
Change this:
public Server (Context context){
this.theMainActivity = new MainActivity();
}
To this:
public Server (Context context){
this.theMainActivity = (MainActivity)context;
}
So that the onCreate is called properly still. If you are new'ing up an activity, it won't be able to set the view properly and follow the correct lifecycle. As #CommonsWare says, you shouldn't ever create an activity via its constructor.

The method findViewById(int) is undefined for the type Json.SnagInfo

So I set up a main_layout.xml shown below with 3 textviews which I then "setContentView" to the main_layout.xml from MainActivity.java as shown below. I then have methods which will be in Java.class (a seperate class in a seperate package) that won't be an activity but will have methods that will be called from MainActivity. The problem is I'm having trouble accessing any of these resources, each of the three findViewById's in Java.class get highlighted under in red and error states: The method findViewById(int) is undefined for the type Json.SnagInfo
What am I doing wrong?
main_layout.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:orientation="vertical" >
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/title" />
<TextView
android:id="#+id/author"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/author" />
<TextView
android:id="#+id/release"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/release"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
// Local Variables
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
}
Json.java
public class Json {
TextView title;
TextView author;
TextView release;
ListView published;
ArrayList<HashMap<String, String>> bookList = new ArrayList<HashMap<String, String>>();
public class SnagInfo extends AsyncTask<URL, Void, String> {
protected void onPreExecute() {
super.onPreExecute();
bookList.clear();
title = (TextView) findViewById(R.id.title);
author = (TextView) findViewById(R.id.author);
release = (TextView) findViewById(R.id.release);
}
}
}
findViewById is a method of Activity class. SnagInfo extends AsyncTask.
If you want to the result of background computation in the activity class you can use interface as a Callback.
Now initialize all your views in activity and set the data there.
Check this link
How do I return a boolean from AsyncTask?
You can also make asynctask an inner class of activity and update ui in onPostExecute

Categories