Reputation: 65
I am having a problem(s) with getting onNewIntent method to work inside Fragment. I have tried everything but nothing seems to work. My project worked perfectly when using activities but when I switched to fragments it stopped working. My idea is that I wanted to make tabs, where one Tab writes to NFC tag and the other Tabs will read data from the NFC Tag. Here is my code for Fragment(writing Tab):
public class Home extends Fragment {
NfcAdapter nfcAdapter;
Button writebtn;
Tag tag;
EditText txtName1, txtName2, txtName3;
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view,savedInstanceState);
nfcAdapter = NfcAdapter.getDefaultAdapter(getContext());
txtName1 = (EditText)view.findViewById(R.id.pName1);
txtName2= (EditText)view.findViewById(R.id.pName2);
txtName3= (EditText)view.findViewById(R.id.pName3);
writebtn=(Button)view.findViewById(R.id.nfcWriteBtn);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.home, container,false);
return v;
}
@Override
public void onResume() {
super.onResume();
if(nfcAdapter !=null){
/* go to phone's nfc settings */
if(!nfcAdapter.isEnabled()){
showNfcSettings();
}
enableForegroundDispatchSystem();
}
}
private void showNfcSettings() {
Intent nfcSettingIntent = new Intent(Settings.ACTION_NFC_SETTINGS);
startActivity(nfcSettingIntent);
}
@Override
public void onPause() {
super.onPause();
disableForegroundDispatchSystem();
}
protected void onNewIntent(Intent intent) {
System.out.print("I am here in Home");
Log.d("my tag", "I am here now");
Toast.makeText(getActivity(), "NfcIntent!", Toast.LENGTH_SHORT).show();
if (intent.hasExtra(NfcAdapter.EXTRA_TAG)) {
// if (nfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Toast.makeText(getActivity(), "NfcIntent!", Toast.LENGTH_SHORT).show();
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
writebtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NdefMessage ndefMessage = createNdefMessage(txtName1.getText().toString(), txtName2.getText().toString(),txtName3.getText().toString());
writeNdefMessage(tag, ndefMessage);
}
});
}
}
private void enableForegroundDispatchSystem() {
Intent intent = new Intent(getActivity(), getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, 0);
IntentFilter[] intentFilters = new IntentFilter[]{};
nfcAdapter.enableForegroundDispatch(getActivity(), pendingIntent, intentFilters, null);
}
private void disableForegroundDispatchSystem() {
nfcAdapter.disableForegroundDispatch(getActivity());
}
private void formatTag(Tag tag, NdefMessage ndefMessage) {
try {
NdefFormatable ndefFormatable = NdefFormatable.get(tag);
if (ndefFormatable == null) {
Toast.makeText(getContext(), "Tag is not ndef formatable!", Toast.LENGTH_SHORT).show();
}
else{
ndefFormatable.connect();
ndefFormatable.format(ndefMessage);
ndefFormatable.close();
Toast.makeText(getContext(), "Tag writen!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e("formatTag", e.getMessage());
}
}
private void writeNdefMessage(Tag tag, NdefMessage ndefMessage) {
try {
if (tag == null) {
Toast.makeText(getContext(), "Tag object cannot be null", Toast.LENGTH_SHORT).show();
return;
}
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// format tag with the ndef format and writes the message.
formatTag(tag, ndefMessage);
} else {
ndef.connect();
if (!ndef.isWritable()) {
Toast.makeText(getContext(), "Tag is not writable!", Toast.LENGTH_SHORT).show();
ndef.close();
return;
}
ndef.writeNdefMessage(ndefMessage);
ndef.close();
Toast.makeText(getContext(), "Tag writen!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e("writeNdefMessage", e.getMessage());
}
}
private NdefRecord createTextRecord(String content) {
try {
byte[] language;
language = Locale.getDefault().getLanguage().getBytes("UTF-8");
final byte[] text = content.getBytes("UTF-8");
final int languageSize = language.length;
final int textLength = text.length;
final ByteArrayOutputStream payload = new ByteArrayOutputStream(1 + languageSize + textLength);
payload.write((byte) (languageSize & 0x1F));
payload.write(language, 0, languageSize);
payload.write(text, 0, textLength);
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload.toByteArray());
} catch (UnsupportedEncodingException e) {
Log.e("createTextRecord", e.getMessage());
}
return null;
}
private NdefMessage createNdefMessage(String content, String content2, String content3) {
NdefRecord ndefRecord = createTextRecord(content);
NdefRecord ndefRecord2 = createTextRecord(content2);
NdefRecord ndefRecord3 = createTextRecord(content3);
NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{ndefRecord, ndefRecord2, ndefRecord3});
return ndefMessage;
}
}
In the Activity that contains tabs I have created this method:
public class DosisHome extends AppCompatActivity {
protected DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mtoggle;
NfcAdapter nfcAdapter;
private Toolbar mtoolbar;
Fragment fragment;
private TextView mName;
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private NavigationView mNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_layout);
mtoolbar = (Toolbar) findViewById(R.id.nav_action);
setSupportActionBar(mtoolbar);
mNavigationView= (NavigationView)findViewById(R.id.nav_view);
mDrawerLayout = findViewById(R.id.drawer_layout);
mtoggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.open, R.string.close);
mDrawerLayout.addDrawerListener(mtoggle);
mtoggle.syncState();
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
tabLayout.setupWithViewPager(mViewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition())
{
case 0:
mViewPager.setCurrentItem(0);
mtoolbar.setTitle("Home");
break;
case 1:
mViewPager.setCurrentItem(1);
mtoolbar.setTitle("Write");
break;
case 2:
mViewPager.setCurrentItem(2);
mtoolbar.setTitle("Read");
break;
case 3:
mViewPager.setCurrentItem(3);
mtoolbar.setTitle("Others");
break;
case 4:
mViewPager.setCurrentItem(4);
mtoolbar.setTitle("Alarm");
break;
default:
mViewPager.setCurrentItem(tab.getPosition());
mtoolbar.setTitle("Home APP");
break;
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
// set item as selected to persist highlight
menuItem.setChecked(true);
switch (menuItem.getItemId()){
case R.id.nav_write:
mViewPager.setCurrentItem(0);
mDrawerLayout.closeDrawers();
mtoolbar.setTitle("Write");
break;
case R.id.nav_read:
mViewPager.setCurrentItem(1);
mDrawerLayout.closeDrawers();
mtoolbar.setTitle("Read");
break;
case R.id.nav_other:
mViewPager.setCurrentItem(2);
mDrawerLayout.closeDrawers();
mtoolbar.setTitle("Others");
break;
case R.id.nav_alarm:
mViewPager.setCurrentItem(3);
mDrawerLayout.closeDrawers();
mtoolbar.setTitle("Alarm");
break;
case R.id.nav_logout:
FirebaseAuth.getInstance().signOut();
finish();
startActivity(new Intent(getApplicationContext(),Login.class));
}
// close drawer when item is tapped
mDrawerLayout.closeDrawers();
return true;
}
});
mDrawerLayout.addDrawerListener(
new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// Respond when the drawer's position changes
}
@Override
public void onDrawerOpened(View drawerView) {
// Respond when the drawer is opened
}
@Override
public void onDrawerClosed(View drawerView) {
// Respond when the drawer is closed
}
@Override
public void onDrawerStateChanged(int newState) {
// Respond when the drawer motion state changes
}
}
);
}
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
super.onNewIntent(intent);
Toast.makeText(this, "I am in TabsHome", Toast.LENGTH_SHORT).show();
System.out.print("I am here in TabsHome");
Log.d("my tag", "I am here");
// Notify fragment about the new intent
if(fragment instanceof Home){
Log.d("my tag", "I am here");
Home hm = (Home) fragment;
hm.onNewIntent(intent);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_dosis_home, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
if(mtoggle.onOptionsItemSelected(item)){
return true;
}
//noinspection SimplifiableIfStatement
if (item.getItemId()== R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
Home home= new Home();
return home;
case 1:
Writer write = new Writer();
return write;
case 2:
Reader read= new Reader();
return read;
case 3:
Others other= new Others();
return other;
case 4:
Alarm alarm= new Alarm();
return alarm;
}
return null;
}
@Override
public int getCount() {
// Show 3 total pages.
return 5;
}
/*to set text instead of icons*/
public CharSequence getPageTitle(int position){
return null;
}
}
}
My AndroidManifest for Activity with tabs :
<activity android:name=".TabsHome"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait"
android:launchMode="singleTop">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
I have researched similar questions with solutions but none of them seems to work with my implementation. What am I doing wrong here?
Upvotes: 1
Views: 3985
Reputation: 6986
In activity do this:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)//This will be used in NFCCardFragment
}
when the setIntent is called in activity, in the fragment onResume
method is called automatically
!
So you can get intent from it like this:
override fun onResume() {
super.onResume()
nfcAdapter?.let { adapter ->
if (adapter.isEnabled)
adapter.enableForegroundDispatch(
requireActivity(),
nfcPendingIntent,
nfcFilters,
nfcTechLists
)
}
//this part is the point
requireActivity().intent?.let {
//Do whatever you want!
resolveNFCIntent(it)
}
}
Upvotes: 3
Reputation: 323
what you can do is to use an interface.
in your Activity use:
private interfaceName listener;
public void setNewIntentListner(Fragment fragmentName) {
listener = fragmentName;
}
@Override
protected void onNewIntent(Intent intent) {
if(listener != null){
listener.newIntent(intent);
}
return;
}
The interface:
public interface InterfaceName{
void newIntent(Intent intent);
}
Finally in your fragment:
public class fragmentName extends Fragment implements interfaceName{
private MainActivity mainActivity;
@Override
public void onStart() {
super.onStart();
mainActiviyt = (MainActivity)getActivity();
mainActivity.setNewIntentListner(this);
}
@Override
public void newIntent(Intent intent) {
// here you have your intent in your fragment
}
}
Upvotes: 0
Reputation: 1753
I'm not sure if you guys solved this. But, I was trying to do the same have a NFC fragment to read the tags, the problem for me was the intents were not being initialized at the right time in the fragment as soon as I moved them to the activity the onNewIntent started working and from there I sent the intent to the fragment to be processed. Not sure if this is still useful or not, if there is a better way feel free to share it because I want to have the fragment completely independent from the activity if it is possible.
Upvotes: 1
Reputation: 3480
The problem for you is, your fragment
variable is never initialized and hence the fragment instanceof Home
condition never works.
You want to pass the newIntent data to Home
fragment which resides in ViewPager
as the first page (i.e 0th index). So you can ask your SectionsPagerAdapter
to give you the Home
fragment via getItem(int position)
method. But if you look at your implementation of getItem()
method, you are always returning new Instance of fragment with
case 0:
Home home= new Home();
return home;
So, if you call mSectionAdapater.getItem()
, it'll give you another instance of Home Fragment and not the one which is being displayed currently. So you need to do some changes first in your SectionsPagerAdapter
I showed below.
Change your SectionsPagerAdapter
with this:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragments = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
mFragments.add(new Home());
mFragments.add(new Writer());
mFragments.add(new Reader());
mFragments.add(new Others());
mFragments.add(new Alarm());
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
// Show 3 total pages.
return mFragments.size();
}
/*to set text instead of icons*/
public CharSequence getPageTitle(int position) {
return null;
}
}
now, change your onNewIntent()
method in your Activity with:
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
super.onNewIntent(intent);
Toast.makeText(this, "I am in TabsHome", Toast.LENGTH_SHORT).show();
System.out.print("I am here in TabsHome");
Log.d("my tag", "I am here");
// Notify fragment about the new intent
Fragment fragment = mSectionsPagerAdapter.getItem(0);
if(fragment instanceof Home){
Log.d("my tag", "I am here");
Home hm = (Home) fragment;
hm.onNewIntent(intent);
}
}
Upvotes: 0
Reputation: 177
onNewIntent belongs to Activity so you cannot have directly it in your fragment. What you can do is pass the data to your fragment from your activity when it arrives in onNewIntent provided you have the reference to the fragment.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
List<Fragment> allFragments = getSupportFragmentManager().getFragments();
Fragment fragment;
for (Fragment fragment : allFragments) {
if (fragment instanceof Home) {
Home frgHome = (Home) fragment;
frgHome.onNewIntent(intent);
}
}
}
Upvotes: 0