I have CustomLayout class declared in a library customAndroidLibrary. This CustomLayout extends ViewGroup. Now I want to use this CustomLayout in my layout.xml which is in my project. I have included this library in my project.
CustomLayout class
package com.android.custom;
public class CustomLayout extends ViewGroup {
.....
}
layout.xml
<com.android.custom.CustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/animation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.android.custom.CustomLayout>
MainActivity
package com.android.ui;
public class MainActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
}
}
But it is throwing ClassNotFoundException.
Even it is not detecting my Activity also if I am using the custom view in layout.xml
If I am using simple TextView in layout.xml. Then it is not giving any error.
Solved it on my own.
<com.android.custom.CustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
class="com.android.custom.CustomLayout"
android:id="#+id/animation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.android.custom.CustomLayout>
Related
I am working in MVVM design pattern.
I want to use dataBinding or RXJava in order to notify the View when the model has changed.
dataBinding can do it inside xml.
but i want to notify the Activity on a change in the model and do something more complicated.
let's assume i want my TextView to change color when text in not empty.
can you help me to do it via dataBinding or RXJava ?
here is my code:
xml
<?xml version="1.0" encoding="utf-8"?>
<data>
<variable
name="viewModel"
type="edi.com.mydatabindingsimple.MyViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="#={viewModel.txt}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#={viewModel.txt}" />
</LinearLayout>
Activity
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import edi.com.mydatabindingsimple.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
MyViewModel viewModel = new MyViewModel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setViewModel(viewModel);
}
}
viewModel
import android.databinding.BaseObservable;
import android.databinding.Bindable;
public class MyViewModel extends BaseObservable{
private String txt;
#Bindable
public String getTxt() {
return txt;
}
public void setTxt(String txt) {
this.txt = txt;
notifyPropertyChanged(edi.com.mydatabindingsimple.BR.txt);
}
}
What you can do is create a callback mechanism to trigger a method in your Activity. This will still notify the ViewModel first, but the effect will be the same.
You can create a new interface (or add it inside the ViewModel)
public interface ViewModelCallback{
void ActionCallback();
}
In your Activity:
public class MainActivity extends AppCompatActivity implements ViewModelCallback
In your ViewModel
private ArrayList<ViewModelCallback> callbacks = new ArrayList<>();
public void notifyCallbacks(){
for(ViewModelCallback c : callbacks){
if(c != null){
c.ActionCallback
}
}
}
public void addCallback(ViewModelCallback c){
callbacks.add(c);
}
Call notifyCallback after your NotifyPropertyChanged().
And don't forget to add your activity as a callback in onCreate
viewModel.addCallback(this)
You should also remove it in onDestroy.
I want to create a very simple app. The app should consists of 2 views. In both views are one button. By clicking the button the view should change.
Here is my folder structure
I have two activitys and two activity_layouts. As you can see OverviewActivity isn't inside the activity folder. When I place it into the folder I get this structur:
Why is the activity folder away? Can you give me a little explanation?
Ok, but in this question I use the first folder structur.
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="company.useradministration.activity.LoginActivity">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="btnOverview"
android:text="go to overview"/>
</RelativeLayout>
activity_overview.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".activity.OverviewActivity">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="btnLogin"
android:text="go to login"/>
</RelativeLayout>
LoginActivity
package company.useradministration.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import company.useradministration.R;
public class LoginActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
}
public void btnOverview(View view){
setContentView(R.layout.activity_overview);
}
}
OverviewActivity
package company.useradministration.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import company.useradministration.R;
public class OverviewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overview);
}
public void btnLogin(View view){
setContentView(R.layout.activity_login);
}
}
Okay. When I start the app, I see a button with the text "go to view". After pressing this button, the view changed. Now I see a button with the text "go to overview". When I press this button, the app crashes with the error:
java.lang.IllegalStateException: Could not find method btnOverview(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:307)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:266)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18439)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5085)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
at dalvik.system.NativeStart.main(Native Method)
UPDATE:
Here is the explained answer:
You have a activity_overview.xml with it's class OverviewActivity.
In your activity_overview.xml you set the android:onClick="btnLogin" to the button and you have:
public void btnLogin(View view){
setContentView(R.layout.activity_login);
}
in your OverviewActivity so when user clicks this button it changes the contentview successfully.
The question here is:
Why does the app crashes when you click on the button in activity_login.xml to change the contentview back to activity_overview.xml?
Simple. Because you have set the onclick method in your LoginActivity but you aren't switching to that activity but just changing the layout. So when the button to go back to overview content is clicked the app searches for the function in you OverviewActivity because the activity didn't swithed to LoginActivity. It has just changed the content and there is no function called btnOverview in your OverviewActivity. So here you have 2 solutions:
1- Create two RelativeLayouts in just one xml file and than setVisibility of each layouts on button click.
So for that you have to:
Create only one activity instead of two different and in it's xml file use this code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/overview"
android:visibility="gone">
<Button
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:text="go to login"
android:id="#+id/go_to_login"
android:layout_height="wrap_content" />
//Do your stuff here for overview content
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/login">
<Button
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:text="go to overview"
android:id="#+id/go_to_overview"
android:layout_height="wrap_content" />
//Do your stuff here for login content
</RelativeLayout>
</RelativeLayout>
This code has 2 RelativeLayouts. The first one with id:overview is of the overview content and it's visibility is gone and the second RelativeLayout with id:login has the visibility visible by default (Change the two layouts visibility as desired).
Than in your MainActivty.java (call it as you wish) you can change the visibility of these views like this:
public class MainActivity extends AppCompatActivity {
Button goToOverview, goToLogin;
RelativeLayout overview, login;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remember to change the content to match your xml file name
setContentView(R.layout.activity_main);
//Buttons
goToOverview = (Button) findViewById(R.id.go_to_overview);
goToLogin = (Button) findViewById(R.id.go_to_login);
//Layouts
overview = (RelativeLayout) findViewById(R.id.overview);
login = (RelativeLayout) findViewById(R.id.login);
goToOverview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login.setVisibility(View.GONE);
overview.setVisibility(View.VISIBLE);
}
});
goToLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
overview.setVisibility(View.GONE);
login.setVisibility(View.VISIBLE);
}
});
}
In this way you can switch to two different layout without any problem.
Edit: You can achieve this also with this solution but the difference between the first solution and this solution is just that you will have 2 xml files instead of one.
2nd- You will have one java class file (in this example I will take OverviewActivityas example) and 2 different layout files (Which you already have: activity_login.xml and activity_overview.xml).
So in your activity_overview.xml change this line: tools:context=".activity.OverviewActivity" to tools:context=".OverviewActivity" as you said that you are using the first folder structure where the OverviewActivity file is out of the activity folder.
Than in your OverviewActivity make the following changes:
public class OverviewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overview);
}
public void btnLogin(View view){
setContentView(R.layout.activity_login);
}
public void btnOverview(View view){
setContentView(R.layout.activity_overview);
}
}
That's it. Please comment if you are having any problem with the code. I will be glad to help your further more.
Hope this can solve your issue.
Regards
I think this is your problem:
public void btnOverview(View view){
setContentView(R.layout.activity_overview);
}
This changes the layout for the current activity LoginActivity to activity_overview which contains the button thats looking for the btnLogin method
You are successfully changing the layout, but your staying in the same activity, so the new layout is looking for a method that exists in the other activity
Instead change the above code to this:
public void btnOverview(View view){
Intent intent = new Intent(this, OverviewActivity.class);
startActivity(intent);
}
And in OverviewActivity
public void btnLogin(View view){
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
I think you can use this as a help. I'm newbie myself to android java programming, but I believe you have to create intent to move to another activity. Additionally be sure to add your Activity to AndroidManifest.xml. That's all I think. If I'm wrong I'll be happy if someone more experienced will correct me :)
I am facing java.lang.IllegalStateException Required view 'splash_text' but I have included it in the xml.
I am using Butterknife to Bind the views.
compile 'com.jakewharton:butterknife:7.0.1'
Xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_orange_light">
<com.CustomTextView
android:id="#+id/splash_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
Activity :
#Bind(R.id.splash_text)
CustomTextView mSplashTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
ButterKnife.bind(this);
mSplashTv.setText("Splash");
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
finishSplash();
}
},3000);
}
Application is crashing at the line mSplashTv.setText("Splash");
Log :
Caused by: java.lang.IllegalStateException: Required view 'splash_text' with ID 2131492944 for field 'mSplashTv' was not found. If this view is optional add '#Nullable' annotation.
at butterknife.ButterKnife$Finder.findRequiredView(ButterKnife.java:140)
at com.sonymix.activities.SplashActivity$$ViewBinder.bind(SplashActivity$$ViewBinder.java:12)
at com.sonymix.activities.SplashActivity$$ViewBinder.bind(SplashActivity$$ViewBinder.java:9)
at butterknife.ButterKnife.bind(ButterKnife.java:319)
at butterknife.ButterKnife.bind(ButterKnife.java:237)
at com.sonymix.activities.BaseActivity.onCreate(BaseActivity.java:16)
at com.sonymix.activities.SplashActivity.onCreate(SplashActivity.java:33)
at android.app.Activity.performCreate(Activity.java:5372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2267)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2359)
at android.app.ActivityThread.access$700(ActivityThread.java:165)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1326)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5455)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
at dalvik.system.NativeStart.main(Native Method)
Update:
BaseActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(this);
}
Support Library used:
compile 'com.android.support:appcompat-v7:23.1.1'
Remove binding from base activity. When ButterKnife bind in base class, your layout not inflated yet.
Also you can add #Nullable annotation to field.
It's because your layout is not inflated yet. If you are using BaseActivity, do something like this :
public abstract class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(this.getLayoutContentViewID());
ButterKnife.bind(this); //Configure Butterknife
}
public abstract int getLayoutContentViewID();
}
Next, in your MainActivity :
public class MainActivity extends BaseActivity {
#BindView(R.id.main_activity_coordinator_layout) CoordinatorLayout coordinatorLayout;
...
#Override
public int getLayoutContentViewID() { return R.layout.activity_main; }
...
}
Check your support Library version. I was getting the above error since i upgraded support library to 23 version. may be that is causing error.NavigationView get/find header layout
pardon me if this is a stupid error. there are two fragments in my activity layout (xml) and in order to let them communicate i am trying to get the instance of one fragment inside my main activity. i have done it earlier but this time it throws erro (required videolisting fragment but found fragment) i am not sure what i have given wrong. might be just a silly mistake. can you please assist. Thanks in advance.
below is code snippet:
public class VideoListingActivity extends ActionBarActivity implements FilterFragment.OnFilterItemSelectedListener{
public VideoListFragment videoListFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_listing);
videoListFragment =(VideoListFragment) getSupportFragmentManager().findFragmentById(R.id.frg_video_listing_video_listing_fragment);
}
below is the layout:
<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"
tools:context="my activity context">
<fragment
android:layout_width="match_parent"
android:layout_height="#dimen/filter_fragment_height"
android:name="com.text1.text2.text3.pkg.FilterFragment"
android:id="#+id/frg_video_listing_filter_fragment"
></fragment>
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.text1.text2.text3.pkg.VideoListFragment"
android:id="#+id/frg_video_listing_video_listing_fragment"
></fragment>
</RelativeLayout>
Below is fragment class code
package com.rrdtech.vidyavaan.android.Fragments;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.rrdtech.vidyavaan.android.R;
public class VideoListFragment extends ListFragment {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.video_list_fragment,container,false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
}
}
Below is stack trace
Error:(22, 91) error: inconvertible types
required: VideoListFragment
found: Fragment
Maybe you need to add the class attribute in XML.
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.text1.text2.text3.pkg.VideoListFragment"
class="com.text1.text2.text3.pkg.VideoListFragment"
android:id="#+id/frg_video_listing_video_listing_fragment"/>
You Need to know
You are using support library for Fragment using
getSupportFragmentManager(), In this case you should always use support package classes.
VideoListFragment extending android.app.ListFragment; instead of android.support.v4.app.ListFragment; (this thing causes the error). And make sure fragment layout has ListView with "#android:id/list" id.
I'm having problem with ActionBar and app-compat-v21.
ActionBar is shown everywhere except PreferenceActivity
I tried to follow recommendations and made it with Fragments:
public class PrefsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
and
public class PrefsActivity extends PreferenceActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new PrefsFragment()).commit();
}
}
However, there's no ActionBar.
BTW, in Styles.xml is set <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
What's wrong?
In order to use the new appcompat v21 you have to:
extend the AppCompatActivity
use a theme which inherits from Theme.AppCompat.(for example Light or NoActionBar)
The PreferenceActivity doesn't extend the AppCompatActivity.
It is the reason why there is no actionbar in your code.
As solution you can create a PreferenceFragment as you are doing and use it in a standard AppCompatActivity.
UPDATED 12/06/2015
With the new 22.1+ appcompat you can use also the AppCompatDelegate to extend AppCompat's support to any Activity.
You can check this official link to AppCompatPreferenceActivity, where you can find an example of this technique.
With the app compat the toolbar needs to be defined in the layout. You can create a layout for the Settings Activity with the toolbar and then add the preference fragment.
For example:
activity_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
layout="#layout/toolbar" />
<fragment
android:id="#+id/settings_fragment"
android:name="com.bla.bla.MyPreferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/toolbar" />
</RelativeLayout>
SettingsActivity:
public class SettingsActivity extends ActionBarActivity{
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar actionbar = (Toolbar) findViewById(R.id.toolbar);
actionbar.setTitle("Settings");
actionbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SettingsActivity.this.finish();
}
});
}
MyPreferenceFragment:
public static class MyPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);;
}
}
edit: Updated the answer to use ActionBarActivity instead of the deprecated PreferenceActivity