Problem
I am getting java.lang.IllegalStateException: Could not find method secondOne(View) in a parent or ancestor Context for android:onClick attribute defined on view class androidx.appcompat.widget.AppCompatButton
What I've done?
In manifest, I have activities:
<activity
android:name=".MainActivity"
android:label="#string/app_name">
</activity>
<activity
android:name=".LeadActivity"
android:label="#string/app_name">
</activity>
<activity
android:name=".MainMenu"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
In game_menu.xml, I have two buttons. First has android:onClick="firstOne" property, second has android:onClick="secondOne" property.
In class MainMenu, which extends AppCompatActivity I have two methods:
public void firstOne(View view) {
Intent intent = new Intent(MainMenu.this, MainActivity.class);
startActivity(intent);
}
public void secondOne(View view) {
Intent intent = new Intent(MainMenu.this, LeadActivity.class);
startActivity(intent);
}
When I tap on the first button, my MainActivity.class runs, as it should.
But when I tap on the second button this error appears. java.lang.IllegalStateException: Could not find method secondOne(View) in a parent or ancestor Context for android:onClick attribute defined on view class androidx.appcompat.widget.AppCompatButton
Please, help. What am I doing wrong?
UPD
full MainMenu class code:
public class MainMenu extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_menu);
//Hide the status bar and the action bar
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
public void firstOne(View view) {
Intent intent = new Intent(MainMenu.this, MainActivity.class);
startActivity(intent);
}
public void secondOne(View view) {
Intent intent = new Intent(MainMenu.this, LeadActivity.class);
startActivity(intent);
}}
UPD2
game_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/sky"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="-16dp" />
<Button
android:id="#+id/button_start"
android:layout_width="175dp"
android:layout_height="76dp"
android:layout_marginTop="200dp"
android:background="#color/black"
android:onClick="firstOne"
android:text="#string/playButtonText"
android:textColor="#color/white"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="#+id/imageView"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button_lead"
android:layout_width="175dp"
android:layout_height="76dp"
android:layout_marginTop="312dp"
android:background="#color/black"
android:onClick="secondOne"
android:text="#string/leaderboardButtonText"
android:textColor="#color/white"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="#+id/imageView"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
That was terrible one. I've spent a lot of time on this, but the answer was simple. Always care about onCreate method and actually setContentView(R.layout.); line. I've been copy-pasting and tried to create classes with the same layout.
Related
Hello!
I'm just starting in Android Studio. I searched for a matching question but no joy, please yell out if you've seen this one already!
My main activity has a single button which opens the second activity, the button works and it opens. But the second activity shows as a blank screen instead of the text that should be there.
Apologies for any irrelevant copy/paste!
Manifest:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat.NoActionBar" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".fiveThreeOne"
android:label="#string/title531">
</activity>
</application>
Main activity:
<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:textColor="#ffdedede"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fiveThreeOne"
android:textAllCaps="false"
android:id="#+id/open531btn"
android:layout_below="#+id/mainTitle"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="38dp" />
</RelativeLayout>
Button code in main class
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button open531button = (Button) findViewById(R.id.open531btn);
open531button.setOnClickListener(new OnClickListener(){
public void onClick(View v){
startActivity(new Intent(MainActivity.this, fiveThreeOne.class));
}
});
}
Second activity 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">
<TextView
android:text="#string/title531"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:editable="false"
android:textSize="35sp"
android:id="#+id/title531"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Thanks!
It sometimes happens when instead of overloading
protected void onCreate(Bundle savedInstanceState) {
you end up overloading
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState)
instead.
Make sure the onCreate with only savedInstanceState as a argument is overloaded.
Have you set the layout for your activity in the line setContentView() like this. Here activity_second is the activity layout of my SecondActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
if not then your activity will show up as blank.
Hope this solves your problem.
Check weather you have set the correct layout for the setContentView() method of your second activity.
You can just go to dependencies in build.gradle file and add this line there.. & try.
implementation 'com.android.support:appcompat-v7:28.0.0-alpha1'
In my case, I changed device in Android Virtual Divice Manager and this fix problem
Why do my android apps keep closing when using 2 intent? when I delete one of them, it's work. especially if I delete the "Reg" Button in the java files.
Thanks
XML Files:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginAct">
<TextView
android:id="#+id/daftar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/daftar"
android:textAlignment="center"
android:textColor="#color/Linktext"
android:clickable="true"
android:focusable="true"
android:layout_marginTop="10dp">
</TextView>
<Button
android:id="#+id/pass"
android:layout_width="wrap_content"
android:layout_height="23dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="25dp"
android:background="#color/colorPrimaryDark"
android:clickable="true"
android:focusable="true"
android:text="#string/lewat"
android:textColor="#color/textwhite" />
Java Files (If I deleted the "Reg" Button from this file, the app is working, but otherwise it will force close after the splash screen):
package com.soerja.ngalamhistory;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class LoginAct extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_login);
Button Pass = (Button) findViewById(R.id.pass);
Button Reg = (Button) findViewById(R.id.daftar);
Pass.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(LoginAct.this, MainActivity.class);
startActivity(intent);
}
});
Reg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(LoginAct.this, RegisAct.class);
startActivity(intent);
}
});
}
}
AndroidManifest Files:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.soerja.ngalamhistory">
<application
android:allowBackup="true"
android:icon="#mipmap/logo"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".SplashAct"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".LoginAct"
android:label="#string/applogin"
android:theme="#style/LogTheme"></activity>
<activity
android:name=".MainActivity"
android:label="#string/home"
android:theme="#style/AppTheme"></activity>
<activity android:name=".RegisAct"
android:label="#string/appdaftar"
android:theme="#style/LogTheme"></activity>
</application>
</manifest>
I would really appreciate your help because this is my school project :)
You are casting a TextView into a Button. Probably the problem is a invalid cast exception.
In XML, you define the "daftar" as a TextView, but in java you are trying to use it as a Button.
Change it
Button Reg = (Button) findViewById(R.id.daftar);
To it
TextView Reg = (TextView) findViewById(R.id.daftar);
Or change your XML implamentation, defining "daftar" as a Button
here you are using your text view id
android:id="#+id/daftar"
as a reference to declaring button
Button Reg = (Button) findViewById(R.id.daftar);
so i think ,that may be the reason for crash
try this method :
add this in your text xml code:
android:onClick="daftar"
add for java class use this:
public void daftar(View v)
{
Intent intent = new Intent(this, RegisAct.class);
startActivity(intent);
}
and remove the old java code you used for this text view:
i hope this helps.
I am new to java coding and Android Studio, so please bear with me. However, I am trying to get a login screen to start after the splash screen and the app crashes after the splash screen. The splash screen works no problem. Anyways, here is the first set of code and this is the splash screen code in Main activity.
package com.example.xxxx.safetyxxxxxxx;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView tv;
ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
tv = (TextView) findViewById(R.id.tv);
iv = (ImageView) findViewById(R.id.imageView);
Animation mine = AnimationUtils.loadAnimation(this, R.anim.transition);
final Intent go = new Intent(MainActivity.this, LoginPageActivity.class);
//set duration ... 1 second ... :p
mine.setDuration(1000);
tv.startAnimation(mine);
iv.startAnimation(mine);
//make a thread to go to second activity...
Thread t = new Thread() {
#Override
public void run() {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
MainActivity.this.startActivity(go);
finish();
}
}
};
t.start();
}
}
this is the Login Page activity called "LoginPageActivity.java" that I would like to have the app go to after the splash screen.
package com.example.xxxx.safetyxxxxxxx;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import static com.example.xxxx.safetyxxxxxxx.R.layout.activity_login_page;
public class LoginPageActivity extends AppCompatActivity implements View.OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_login_page);
findViewById(R.id.textViewSignUp).setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.textViewSignUp:
startActivity(new Intent(this, SignUpActivity.class));
break;
}
}
}
This is the androidmanifest.xml code
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxxx.safetyxxxxxxx">
<application
android:name=".Database"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
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>
<activity android:name=".LoginPageActivity"
android:label="#string/app_name">
</activity>
<activity android:name=".Main2Activity" />
<activity android:name=".SignUpActivity" />
</application>
</manifest>
Here is the logcat error
1-28 12:55:33.490 7647-7670/com.example.xxxx.safetyxxxxxxx E/AndroidRuntime: FATAL EXCEPTION: Thread-5
Process: com.example.xxxx.safetyxxxxxxx, PID: 7647
android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.xxxx.safetyxxxxxxx/com.example.xxxx.safetyxxxxxxx.LoginPageActivity}; have you declared this activity in your AndroidManifest.xml?
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1932)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1615)
at android.app.Activity.startActivityForResult(Activity.java:4472)
at android.support.v4.app.BaseFragmentActivityApi16.startActivityForResult(BaseFragmentActivityApi16.java:54)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:67)
at android.app.Activity.startActivityForResult(Activity.java:4430)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:720)
at android.app.Activity.startActivity(Activity.java:4791)
at android.app.Activity.startActivity(Activity.java:4759)
at com.example.mike.safetychecker.MainActivity$1.run(MainActivity.java:39)
Also if needed the file activity_login_page.xml code is below
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginPageActivity">
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Hi, Welcome to Safety xxxxxx Please Login or Signup"
android:textAlignment="center"
android:textColor="#android:color/holo_green_dark"
android:textSize="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.995"
tools:layout_editor_absoluteX="0dp"
tools:ignore="MissingConstraints" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Login"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="398dp"
tools:ignore="MissingConstraints" />
<EditText
android:id="#+id/editTextEmail"
android:layout_width="346dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:ems="10"
android:hint="email"
android:inputType="textEmailAddress"
android:text=" email"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="270dp"
tools:ignore="MissingConstraints" />
<EditText
android:id="#+id/Password"
android:layout_width="346dp"
android:layout_height="50dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:ems="10"
android:inputType="textVisiblePassword"
android:text=" Password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="336dp"
tools:ignore="MissingConstraints" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="219dp"
android:layout_height="229dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="#+id/editTextEmail"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/safetyxxxx" />
<TextView
android:id="#+id/textViewSignUp"
android:layout_width="351dp"
android:layout_height="34dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Do Not Have An Account? Click Here"
android:textAlignment="center"
android:textColor="#android:color/holo_green_dark"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.529"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="459dp"
tools:ignore="MissingConstraints" />
</android.support.constraint.ConstraintLayout>
Also there is this transition.xml file contained in a anim folder that might help
<?xml version="1.0" encoding="utf-8"?>
<alpha
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="1.0"
/>
you have to try to open your LoginPageActivity like this way
Paste this code
openActivity();
instead of this
Thread t = new Thread() {
#Override
public void run() {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
MainActivity.this.startActivity(go);
finish();
}
}
};
t.start();
and put this method
public void openActivity()
{
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent go = new Intent(MainActivity.this,LoginPageActivity.class);
startActivity(go);
finish();
}
}, 5000);
}
import this packages
import android.os.Bundle;
import android.os.Handler;
and also mention in your manifest like this
<activity android:name=".LoginPageActivity"
android:label="#string/app_name"/>
You have to declare your Activity in your AndroidManifest.xml. Almost all of your system-related classes have to be declared in it, this includes Activities, Services, BroadCast Receivers. You can read up on how Manifest works over here
Back to your problem, you can fix it by add the following line inside the application tag in your Android Manifest. Remove any intent filters you have applied to it
<activity android:name=".LoginPageActivity" />
Remove :
<intent-filter>
<action android:name="com.example.xxxx.safetyxxxxxxx.LoginPageActivity" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Because there is always remains only one LAUNCHER activity in application. And also intent filter is wrong there.
change LAUNCHER TO DEFAULT in your mainfest, Two launcher is not possible at same time (Assuming MainActivity as LAUNCHER)
</activity android:name=".LoginPageActivity>
<intent-filter>
<action android:name="com.example.xxxx.safetyxxxxxxx.LoginPageActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
use this
<activity android:name=".LoginPageActivity"
android:label="#string/app_name"/>
instead of
<activity android:name=".LoginPageActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="com.example.xxxx.safetyxxxxxxx.LoginPageActivity" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MainActivity.this,com.example.xxxx.safetyxxxxxxx.LoginPageActivity.class);
startActivity(intent);
finish();
}
}, 5000);
//where 5000 is the delayed time
Beginner with Android here.
I have a MainActivity, which generates a String and send it to an ArrayList (singleton pattern). I also have a HistoryActivity, which will display the contents of the ArrayList.
I have the ArrayList being sent to an Array, and activity_history has a ListView with an ArrayAdapter in HistoryActivity. There are buttons on activity_history that will remove an item from the ArrayList (and recreate the Array) and clear the entire ArrayList. However, the ListView does not update automatically (the activity has to be closed and reopened).
I'm currently trying ((BaseAdapter) historyView.getAdapter()).notifyDataSetChanged(); (as seen below), but it is not working. Any advice or guidance would be great.
HistoryActivity.java
public class HistoryActivity extends AppCompatActivity {
DataStorage history = DataStorage.getDataStorage();
String[] historyArray;
private ListView historyView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
}
#Override
protected void onStart() {
super.onStart();
historyView = (ListView) findViewById(R.id.history);
historyArray = history.getHistory().toArray(new String[history.getHistory().size()]);
historyView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, historyArray));
}
/**
* Clear all of history
*/
public void clearHist(View view) {
history.getHistory().clear();
historyArray = history.getHistory().toArray(new String[history.getHistory().size()]);
((BaseAdapter) historyView.getAdapter()).notifyDataSetChanged();
}
/**
* Remove last entry to history
*/
public void clearOne(View view) {
history.getHistory().remove(0);
historyArray = history.getHistory().toArray(new String[history.getHistory().size()]);
((BaseAdapter) historyView.getAdapter()).notifyDataSetChanged();
}
/**
* Change to main view
*/
public void sendMessage(View view) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
activity_history.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="wrap_content"
android:layout_height="wrap_content"
android:background="#000000"
tools:context="com.mattbraddock.mbcgen.HistoryActivity">
<LinearLayout
android:id="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="clearOne"
android:text="Remove Last" />
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="sendMessage"
android:text="Return" />
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="clearHist"
android:text="Clear All" />
</LinearLayout>
<ListView
android:id="#+id/history"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/buttons"
android:layout_alignParentTop="true"
android:paddingBottom="16dp" />
</RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mattbraddock.mbcgen">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:theme="#style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".HistoryActivity"
android:label="Card History"
android:theme="#style/Theme.AppCompat.Dialog"
android:screenOrientation="portrait"></activity>
<!-- ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
The problem is that each time you use
historyArray = history.getHistory().toArray(new String[history.getHistory().size()]);
you change the reference of the historyArray variable to another newly created array, but the adapter still holds a reference to the old array which you passed to the adapter constructor.
My suggestion would be to replace you array with an ArrayList and use clear(), add(), and addAll() methods. Also avoid reassigning the historyArray if you want to keep the reference to the data of the adapter, and for notifyDataSetChanged() to work.
I would save a reference to the adapter and use an Arraylist instead of an array.
historyView = (ListView) findViewById(R.id.history);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, history.getHistory());
historyView.setAdapter(adapter);
Then when you want to update the view, then just modify the adapter.
adapter.clear();
Or
adapter.remove(0);
I am developing an Android app consisting of two activites so far. The first activity (MainActivity) is started when the app is launched or when a QR code is scanned. The MainActivity starts the second activity (NFCActivity) when the user presses a button. The NFCActivity waits for the user to tap a NFC token, reads out data from the token, and returns the read data to the MainActivity.
This works fine if the app is started manually. If the app is started by scanning a QR code, taping the NFC tag does not invoke the NFCActivity's onNewIntent() method as exepcted, but instead creates a new instance of the NFCActivity on top of the already displayed one.
The enableForegroundDispatch() method is called and FLAG_ACTIVITY_SINGLE_TOP should be set. Relevant source code of a minimal example is provided below. Any help would be highly appreciated!
MainActivity:
public class MainActivity extends Activity {
private EditText dataRead;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
dataRead = (EditText) findViewById(R.id.data);
final Button readKeyButton = (Button) findViewById(R.id.readNFC);
readKeyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent keyIntent = new Intent(MainActivity.this,
NFCActivity.class);
keyIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(keyIntent, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (requestCode == 1) {
String result = intent.getExtras().getString("resultData");
this.dataRead.setText(result);
}
}
}
Main Activity's GUI:
<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=".MainActivity" >
<Button
android:id="#+id/readNFC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="127dp"
android:text="Read NFC Tag" />
<EditText
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/readNFC"
android:layout_centerHorizontal="true"
android:layout_marginBottom="85dp"
android:ems="10" >
<requestFocus />
</EditText>
</RelativeLayout>
NFCActivity:
public class NFCActivity extends Activity {
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.read_nfc);
mAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// // Setup an intent filter for all MIME based dispatches
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter td = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
mFilters = new IntentFilter[] { ndef, td };
//
// // Setup a tech list for all NfcF tags
mTechLists = new String[][] { new String[] { NfcV.class.getName(),
NfcF.class.getName(), NfcA.class.getName(),
NfcB.class.getName() } };
}
#Override
public void onResume() {
super.onResume();
if (mAdapter != null)
mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters,
mTechLists);
}
#Override
public void onPause() {
super.onPause();
if (mAdapter != null)
mAdapter.disableForegroundDispatch(this);
}
#Override
public void onNewIntent(Intent intent) {
Log.d("TEST", "onNewIntent() called.");
// READ THE NFC TAG HERE [SKIPPED FOR MINIMAL EXAMPLE]
// Return dummy data for test
Intent result = new Intent();
result.putExtra("resultData", "DUMMY DATA");
setResult(1, result);
finish();
}
}
NFCActivity's GUI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#303030"
android:paddingLeft="30dp"
android:paddingRight="30dp" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Tap your NFC tag.."
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF8811"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.nfcqrtest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="test.nfcqrtest.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="test.org" android:pathPrefix="/testapp" />
</intent-filter>
</activity>
<activity
android:name=".NFCActivity"
android:windowSoftInputMode="stateHidden" android:screenOrientation="portrait" android:launchMode="singleTop">
</activity>
</application>
</manifest>
In case somebody is facing a similar problem: I was finally able to overcome the issue described above by setting the android:launchMode property for the MainActivity to singleInstance.