After migrating to AndroidX: Cannot instantiate class: androidx.appcompat.widget.ShareActionProvider - android

I migrated to AndroidX (using the wizard in Android Studio), and I'm having problems with the share action provider. The wizard changed (among many other things) app:actionProviderClass="android.support.v7.widget.ShareActionProvider" to app:actionProviderClass="androidx.appcompat.widget.ShareActionProvider", in my detailactivity.xml file.
The app compiles fine, and runs fine, too -- so long as I install it on my device over USB. However, if I compile a signed APK, and install that, I get the following runtime error (when starting the detailfragment):
W/SupportMenuInflater: Cannot instantiate class: androidx.appcompat.widget.ShareActionProvider
I didn't notice this problem while developing, since I run/test the app on my device through USB. However, when I'm now testing the (signed/minified) APK, the SHARE button does not work. How can I troubleshoot and fix this? For instance, why does it fail on the signed/minified APK fail, while it works fine when installing on same device through USB?
It's hard to tell specifically where (in the code) the warning occurs, since the code in the APK is minified. Perhaps I could create an APK where the code is not minified, so I'd get proper references to lines in the source code (in Android Studio LogCat)?
For reference, here is an excerpt from the class where the warning occurs. I'm assuming the warning occurs somewhere here, as this is what's referencing the shareActionProvider?
import androidx.appcompat.widget.ShareActionProvider;
public class ScreenSlidePageFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private ShareActionProvider mShareActionProvider;
public ScreenSlidePageFragment() {
setHasOptionsMenu(true); // only the share button
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.detailfragment, menu);
MenuItem menuItem = menu.findItem(R.id.action_share);
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
if (mShareActionProvider != null && mImageData != null) {
mShareActionProvider.setShareIntent(createShareImageIntent());
}
}
}

I got some help on #android-dev (IRC), and it seems the problem was that the minifier (for some reason) removes the androidx.appcompat.widget.ShareActionProvider class. Turning off minification produced a working APK.
The fix was to update my proguard-rules.pro file with a new "keep" line, to prevent it from removing the class. From before, I had a similar rule for the old Android Support Library, so I added the second line below and now it works.
-keep class android.support.v7.widget.** { *; }
-keep class androidx.appcompat.widget.** { *; }
thanks #melatonina!

Related

Default Template on Android Studio deprecated

Earlier I was asking about how to come over from Windows phone development. I didn't just sit and wait for replies I got started.
I installed Android Studio. I learned that it didn't have the 4.4 API by default (the version of Android my new phone will be running) so I located the SDK manager and installed the missing SDK.
The preview pane for the layout editor could not render...I learnt I needed to go to the module settings and change the target there, then to the preview pane drop-down and change the targeted Android version there.
I added a simple button and then realised I have an error with the java ...that I have yet to touch!
public class MainDisplay extends ActionBarActivity {
ActionBarActivity is deprecated.
...but that's the default template!
getMenuInflater().inflate(R.menu.menu_main, menu);
cannot resolve symbol R.
...again, it's default "blank activity" template.
I checked for updates and it is the latest version of Android Studio: 1.2.1.1. My JDK is the latest version: jdk1.8.0_45 (64bit).
Any ideas why my Android Studio (freshly installed today) is generating broken templates or any other ideas about how to fix?
EDIT
I uninstalled Android Studio, the SDK and deleted all folders created by it
then I reinstalled it all. I installed version 1.7 of Java JDK.
I got the same errors on a new project.
This is the source code it generates:
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#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_main, 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.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
As you can see, it is extending the deprecated class, and adding those R's it can't resolve .....and this is before I have done anything.
But for tonight, I have run out of time. I had 7 hours free to start porting my app to Android and it's all gone setting up the dev environment. I wouldn't mind but it's not working and I have no idea why.
According to this video you should only make two changes
After I did this 2 changes all worked fine
For more information about this you have this [1] and this blog
UPDATE 1
After this change, clean your project and Sync Project with Gradle File.
UPDATE 2
If after that you have problem resolving symbol R errors after an SDK update in Android Studio you can follow the steps showing in this blog
First one. The ActionBarActivity is deprecated since API 21 (or 22 maybe) and now you should simply extend from Activity and use AppCompatDelegate. It's a really new feature so I suppose they haven't fixed it yet. I haven't tried using it yet so can't help with that. Even if the ActionBarActivity is deprecated it will work fine so it's not a problem for you.
Second. About the R being not found. The problem is inside your Gradle file (not the app one but the second one). In it you will need to fix a line under the dependencies tag (classpath) and change it to newer version. I can't seem to find the right version now but I have already solved this problem today for my friend so it will definitely work
It is also a bug in a current Android Studio version and after you fix it it will work fine.

Adding cast button to ActionBar using the CastCompanionLibrary

I am trying to add the cast icon to the ActionBar using the CastCompanionLibrary's helper method:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
mDataCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); // This one
return true;
}
I have this as my menu.xml as specified by the PDF that is included with the companion library:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/media_route_menu_item"
android:title="#string/media_route_menu_title"
app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
app:showAsAction="always"/>
</menu>
However, nothing shows up in the ActionBar. No errors are thrown, nothing at all is visible. If I add a different menu item just to see if everything with my menu is set up correctly, that item shows up fine - it is just this cast action menu item that isn't showing up.
I have tried changing the "app" prefixes to "android", but then I get a NullPointerException somewhere deep in the library, and I have tried giving the menu item a different, visible icon. Nothing helps.
In AndroidStudio, the menu preview shows a menu item with the title "Play on...", so it seems like this should work.
What am I doing wrong?
You have to register your chrome-cast as a testing devise for you to be able to detect the chromecast devise from the Android.
Check the full SDK guide
Check the developer console registration. You have to register you chromecast devise in the console here, or else it is not detectable
Update: If nothing works, you may try to publish your app in the chromecast dev console as a last resort.
As mentioned by one of the chromecast developer try to access http://<chromecast-ip>:9222 from browser and see if you are able to see any thing.
Sometimes, these types of errors happen because proguard changes the name of the object and/or functions.
One possible solution is to add these to your progaurd configuration files:
-dontwarn android.support.v7.**
-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
-keep class android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }
I actually had this exact error on the exact line and I didn't have my proguard configured properly for the support library.
In my case after device registration I forgot reboot chromecast device
CastCompanionLibrary and MediaRouteActionProvider are written for AppCompat ActionBar and not Sherlock ActionBar. It is strongly recommended to move your project to AppCompat since Sherlock ActionBar is deprecated so moving to AppCompat is generally a good move for your project; making that move is not difficult (see, e.g. this article)

Console of my Android Studio does not print the log message

I created a Hello, World project in Android Studio to test using System.out.println(). I believe the log message should be printed in the console, but it wasn't. Im using Android Studio AI-130.737825 with JRE:1.7.0_25. The test code follows:
package com.example.consoletest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("please print me in the console");
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The console is not "connected" to the running app because it is run on a different system (be it an emulator, or physical device). The only "connected" part in Android Studio is the LogCat, which can be accessed using the Android tab at the bottom of the IDE.
You should rather print output to LogCat using the Log.* methods, which provides a lot more control and information, in almost the same simplistic way. Additionally, the logcat can be filtered to find exactly what you want.
As #free3om hinted at, Log.* can be used to print out many different outputs to the Logcat. If you want to see just errors, you can use Log.e(String s1, String s2) to see what and where something went wrong. Here's a link to the doc's for Log. http://developer.android.com/reference/android/util/Log.html

Getting robolectric to work with android compatibility package

I try to use Robolectric to run tests for my Android application, which is using the android-support package. In my onCreate() method I call
getSupportLoaderManager().initLoader(0, null, this);
Unfortunately, getSupportLoaderManager() returns null here. Do I have to prepare anything to make the compatiblity classes available to robolectric?
I have the android.jar (android-8) and the android-support-v4.jar in the classpath in my test project, along with robolectric-1.2 snapshot version.
Test class:
#RunWith(RobolectricTestRunner.class)
public class HoebAppActivityTest {
#Test
public void shouldStartActivity() {
final MyActivity activity = new MyActivity();
System.out.println(activity.getSupportLoaderManager()); // return null
activity.onCreate(null);
}
}
Edit:
System.out.println(Robolectric.directlyOnFullStack(activity)
.getSupportLoaderManager());
outputs android.support.v4.app.LoaderManagerImpl#9a90b9 so I guess, I just need to feed this back to the activity? Seems like I am getting closer here.
Edit2: I tried to bind my own ShadowFragmentActivity:
#Implements(FragmentActivity.class)
public class ShadowFragmentActivity extends
com.xtremelabs.robolectric.shadows.ShadowFragmentActivity {
#RealObject
private FragmentActivity realActivity;
#Implementation
public LoaderManager getSupportLoaderManager() {
return Robolectric.directlyOnFullStack(realActivity)
.getSupportLoaderManager();
}
}
bound with
Robolectric.bindShadowClass(ShadowFragmentActivity.class);
This appears to work for the moment. I will have to try further to see if it does what I want. No idea if this is in any way the correct way to go or not.
Robolectric 1.x had poor support for the Android support library. Robolectric 2.0 is significantly better, and has full support for fragments. An alpha was just released today:
<dependency>
<groupId>org.robolectric</groupId>
<artifactId>robolectric</artifactId>
<version>2.0-alpha-1</version>
<dependency>

InflateException: Couldn't resolve menu item onClick handler

I asked this question 6 years ago. In the meantime Android development best practices have changed, and I have become a better developer.
Since then, I have realized that using the onClick XML attribute is a bad practice, and have removed it from any code base I work on.
All of my click handlers are now defined in the code of the app, not the XML layouts!
My reasons for never using onClick are
it is easy to make a mistake in the value of the onClick XML attribute, which will then result in a run-time error
a developer might refactor the name of the click handler method, without realizing it is called from a layout (see reason 1)
finding out which method is actually being called is not always obvious. Especially if the layout is being used by a Fragment
separating the concerns of layout vs behavior is good. Using onClick mixes them up, which is bad!
I hope I have convinced you to never use onClick in a layout :) !
Below is my original question, which is a pretty good illustration of why using onClick is a bad idea.
===
I'm defining menu items in XML, and trying to use the onClick attribute that was added in API 11. When the Activity is launched in an emulator running 4.0.3, the following Exceptions occur:
FATAL EXCEPTION: main
android.view.InflateException: Couldn't resolve menu item onClick handler
onFeedbackMenu in class android.view.ContextThemeWrapper
...
Caused by: java.lang.NoSuchMethodException: onFeedbackMenu
[interface com.actionbarsherlock.view.MenuItem]
at java.lang.Class.getConstructorOrMethod(Class.java:460)
I don't understand what is causing the Exception, since the following method is defined in my Activity
import com.actionbarsherlock.view.MenuItem;
...
public void onFeedbackMenu( MenuItem menuItem ) {
Toast.makeText( this, "onFeedBack", Toast.LENGTH_LONG ).show();
}
My XML menu definition file contains:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
...
<item
android:id="#+id/menu_feedback"
android:icon="#drawable/ic_action_share"
android:showAsAction="ifRoom"
android:title="#string/menu_feedback"
android:onClick="onFeedbackMenu" />
</menu>
For backwards compatibility I am using ActionBarSherlock, and also getting a very similar Exception when I run the App on 2.3.x.
This is a more Complete version of the Stack trace
FATAL EXCEPTION: main
android.view.InflateException: Couldn't resolve menu item onClick handler
onFeedbackMenu in class android.view.ContextThemeWrapper
at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:204)
at com.actionbarsherlock.view.MenuInflater$MenuState.setItem(MenuInflater.java:410)
at com.actionbarsherlock.view.MenuInflater$MenuState.addItem(MenuInflater.java:445)
at com.actionbarsherlock.view.MenuInflater.parseMenu(MenuInflater.java:175)
at com.actionbarsherlock.view.MenuInflater.inflate(MenuInflater.java:97)
...
Caused by: java.lang.NoSuchMethodException: onFeedbackMenu
[interface com.actionbarsherlock.view.MenuItem]
at java.lang.Class.getConstructorOrMethod(Class.java:460)
at java.lang.Class.getMethod(Class.java:915)
at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:202)
... 23 more
I found a solution that worked for me.
Usually the onClick attribute in a layout has the following method
public void methodname(View view) {
// actions
}
On a menu item (in this case Sherlock menu) it should follow the following signature:
public boolean methodname(MenuItem item) {
// actions
}
So, your problem was that your method returned void and not boolean.
In my case, the AndroidManifest.xml of my application (kick-started by the default Eclipse assistant) contained android:theme="#style/AppTheme" in the <application> block.
When debugging the cause of the problem, it turned out that the line
mMethod = c.getMethod(methodName, PARAM_TYPES);
in android.view.MenuInflater/InflatedOnMenuItemClickListener was called with c not being my Activity class but a dubious android.view.ContextThemeWrapper (which of course doesn't contain the onClick handler).
So, I removed the android:theme and everything worked.
Although this is a bit out of date, here is the reason for the exception. When you look into the sources of android API 15 (4.0.3-4.0.4) in the class MenuInflater you will see this method:
public InflatedOnMenuItemClickListener(Context context, String methodName) {
mContext = context;
Class<?> c = context.getClass();
try {
mMethod = c.getMethod(methodName, PARAM_TYPES);
} catch (Exception e) {
InflateException ex = new InflateException(
"Couldn't resolve menu item onClick handler " + methodName +
" in class " + c.getName());
ex.initCause(e);
throw ex;
}
This is were the exception happens, as Junique already pointed out. However the removing of the app theme is just a workaround and no real option. As we see the method tries to find the Callback method on the class of the context item passed. So instead of calling getMenuInflater() in onCreateOptionsMenu you should call new MenuInflater(this), so that this is passed as a context and then the code will work.
You can still use getMenuInflater() for other api versions if you just use an if statement like this:
if (Build.VERSION.SDK_INT > 15)
inflater = getMenuInflater();
else
inflater = new MenuInflater(this);
I don't actually know if the bug happens in api versions under 15 too, so i just generally used the save version.
In my case the problem was that I had both onClick in my menu XML and an onCreateOptionsMenu in my Activity. My onClick was actually faulty (because it pointed to non-existent methods) but I didn't notice this at first because I was testing under Android 2.x, where onClick is not supported and ignored. Once I tested on 4.x though, I started getting this error.
So basically, don't use onClick if you plan on deploying under Android 2.x. It will silently ignore your onClick values until you try running on 3.0+.
I found that I had the same problem with the ActionBar menu items, and their onClick events. What i discovered is that the workstation I'm developing in had run out of memory and needed to be rebooted. The Android VM is now able to resolve the method name referenced.
Your method must accept a MenuItem as its only parameter per here.
public void onMenuItemClickMethod(MenuItem menuItem){
// Do stuff here
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
MenuItem item = menu.findItem(R.id.menu_open);
if (item == null)
return true;
item.setOnMenuItemClickListener
(
new MenuItem.OnMenuItemClickListener ()
{
public boolean onMenuItemClick(MenuItem item)
{ return (showDirectory(item)); }
}
);
return true;
}
public boolean showDirectory (MenuItem item)
{
CheckBox checkBox = (CheckBox) findViewById (R.id.checkBox1);
checkBox.setChecked(true);
}

Categories

Resources