I am sending a downstream message to Android app from php script. But the receiving Android app crushes and I get "Caused by: java.lang.InstantiationException: can't instantiate class mypackage.myactivity$MyGcmListenerService; no empty constructor" on the logcat. I have an empty constructor though. This is the receiver service:
public class MyGcmListenerService extends GcmListenerService {
public static final String UPDATE_COORDINATES = "mypackage.newcoordinate";
LocalBroadcastManager coordintesupdater;
public MyGcmListenerService() { super(); }
#Override
public void onMessageSent(String msgId) {
Log.i("the damn message " + msgId, "sent");
super.onMessageSent(msgId);
}
#Override
public void onDeletedMessages() {
super.onDeletedMessages();
}
#Override
public void onSendError(String msgId, String error) {
super.onSendError(msgId, error);
}
#Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("lat") + ", " + data.getString("lon");
if (message != null && !message.isEmpty()) {
Intent mIntent = new Intent();
mIntent.putExtra(UPDATE_COORDINATES, message);
mIntent.setAction(UPDATE_COORDINATES); //should match the receiver intent filter at the registering
coordintesupdater.sendBroadcast(mIntent);
} else {
Log.i("Received", "empty message");
}
}
}
And this is my manifest where the service is declared explicitly
<service
android:name=".myactivity$MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
I have been researching this the whole evening for hours but I couldn't resolve it. I think the exception is simply broad only to indicate there is a problem, but fails to specify. Can someone point me to the problem?
Based on this
mypackage.MapActivity$MyGcmListenerService
I assume MyGcmListenerService is a nested class. Hovewer it is not static, which means it needs an instance of the class MapActivity as an implicit parameter to be created.
If you don't access MapActivity from MyGcmListenerService you can solve the problem by declaring the latter class static:
public static class MyGcmListenerService extends GcmListenerService
Related
Recently I use MVP to develop an Android App.
But I find an Android Bug(maybe I am wrong)
I have two presenter NewsPresenter and MainPresenter. NewsPresenter is created an instance in a Fragment NewsFragment,and MainPresenter is created an instance in an Activity MainActivty.Of course MainActivity include NewsFragment.Both two presenter have two method to implements which to handle the success response and the fail response.
NewsPresenter
public class NewsPresenter extends IPresenter implements IAdapter.OnRecycleItemClickListener{
#Override
protected void onIRequestSuccess(int requestId, IResponse response) {
Log.e("TAG","onIRequestSuccess:"+requestId);
....
}
#Override
protected void onIRequestFail(int requestId, Throwable throwable) {
Log.e("TAG","onIRequestFail:"+requestId);
...
}
}
MainPresenter
public class MainPresenter extends IPresenter{
public MainPresenter(Context context, IMain iMain) {
super(context);
}
#Override
protected void onIRequestSuccess(int requestId, IResponse response) {
//do nothing
}
#Override
protected void onIRequestFail(int requestId, Throwable throwable) {
//do nothing
}
}
Now,in the NewsPresenter I try to make a network request.In the BasePresenter which is its super class I make a log to show the class which try to execute the network request.And the log is that:
01-02 20:09:28.281 17206-17206/com.chengtao.culture E/BasePresenter: class com.chengtao.culture.presenter.NewsPresenter
this mean NewsPresenter execute the request.
But in the IPresente which is NewsPresenter and MainPresenter super class,I try to make a log to show the class which handle the response.And the log is that:
01-02 20:09:38.352 17206-17206/com.chengtao.culture E/TAG: class com.chengtao.culture.presenter.MainPresenter
This mains that the MainPresenter handle the response.
IPresenter
abstract class IPresenter extends BasePresenter{
IPresenter(Context context) {
super(context);
}
#Override
public void onRequestSuccess(int requestId, BaseResponse response) {
Log.e("TAG",this.getClass().toString());
IResponse response1 = (IResponse) response;
Log.e("TAG","onRequestSuccess");
onIRequestSuccess(requestId,response1);
}
#Override
public void onRequestFail(int requestId, Throwable throwable) {
Log.e("TAG",this.getClass().toString());
if (throwable == null || throwable.getMessage() == null){
throwable = new Throwable("请求超时");
onIRequestFail(requestId,throwable);
}else {
onIRequestFail(requestId,throwable);
}
}
protected abstract void onIRequestSuccess(int requestId, IResponse response);
protected abstract void onIRequestFail(int requestId, Throwable throwable);
}
I am so confused why I use NewsPresenter to make the request,but MainPresenter handle the response?It's not scientific,because the log show that the request is NewsPresenter execute,MainPresenter has no relationship with NewsPresenter just both of them extends IPresenter.
But once I delete the instance of MainPresenter in the Activity,the response will be handled by the NewsPresenter.
To see the whole code: https://github.com/ParadiseHell/cultural-creative/tree/master/app/Culture
I make sure my code is all right,So I don't know is Android bug or it's Java bug.If someone knows,please tell me, thanks.
Firstly your Mvp architecture is wrong. List and Adapter are related to UI, so adapter logic must be with fragment not with the presenter.
You should create something other called "Service Class" which will extend the BaseService in which the real API call is sent.
Every API call must have each separate Service Class.We should set the callback method to that serviceclass object so that when the API call gets executed the callback is received for that particular function.
Sample code which explains the above paragraph.
class GetNewsService extends BaseService {
void doApiCall(){
// execute API call . Put the request related code in BaseService.
}
}
class NewsPresenter {
// I am writing psudeo code only.
void getNews(){
GetNewsService newsService=new GetNewsService();
newsService.setCallBack(new RequestClass(){
#Override
onSuccessMethod(Response response){
// send response object to view class through interface and update adapter there
}
#Override
onFailMethod(Error error){}
});
newsService.doApiCall();
}
}
First I have to say,I use MVP right,just because my library has a bug,and I have fixed it.
In the library,there is a class AsyncHttpClient which is singleton pattern,of course it's wrong,because I can init only one response interface in the whole project,but every presenter has a response interface,so it's bad for handling the response.So I delete singleton pattern,use a public constructor,and the problem disappears.
So it's not Android bug or Java bug,just my fault for thinking less.
I've been trying workarounds/dealing with this problem for weeks and I can't seem to get around it any longer. I have an Android Application that needs to change the device's name before creating a Peer to Peer network.
Because the method is hidden in Android's SDK, I am using reflection. The method I am trying to reflect is located here at line 1305: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
Here is my code trying the reflection:
public class HostStagingActivity extends Activity
{
WifiP2pManager.Channel myChannel; //This channel is created and passed to system services in order for WIFI_P2P to work
WifiP2pManager myManager; //This manager is declared to get the required channel object
...
#Override
protected void onCreate(Bundle savedInstanceState)
{
myManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);//passed to the myReceiver listener class
myChannel = myManager.initialize(this, getMainLooper(), null);//passed to the myReceiver listener class
...
Method method1 = null;
try
{
method1 = myManager.getClass().getMethod("setDeviceName", new Class[] {WifiP2pManager.Channel.class, String.class, WifiP2pManager.ActionListener.class });
method1.invoke(myChannel, NETWORK_NAME, new WifiP2pManager.ActionListener()
{
public void onSuccess()
{
Toast.makeText(getApplicationContext(), "DeviceName Changed Successfully!", Toast.LENGTH_SHORT).show();
//Code for Success in changing name
}
public void onFailure(int reason)
{
Toast.makeText(getApplicationContext(), "DeviceName Change Returned Failure!", Toast.LENGTH_SHORT).show();
//Code to be done while name change Fails
}
});
}
However, this causes runtime error:
Caused by: java.lang.IllegalArgumentException: expected receiver of type android.net.wifi.p2p.WifiP2pManager, but got android.net.wifi.p2p.WifiP2pManager$Channel
at java.lang.reflect.Method.invokeNative(Native Method)
Why is the method expecting a WifiP2pManager object when I am clearly passing it a WifiP2pManager.Channel class in my code? Just for fun, when I pass it the arguements it expects, it claims the method was expecting three arguements and I only gave it two.
Can anybody with more reflection experience help me out?
I am encountering following binder.proxy exception every time i declare and run two services. One service runs in different Process(Private to app) and another service runs in same process as My Application is running in(Default App Process) with a Binder Implementation.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.service.check"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:name="com.service.check.MainApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<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>
<service
android:name="com.service.check.SecondService"
android:exported="false"/>
<service
android:name="com.service.check.FirstService"
android:process=":newProcess" >
</service>
</application>
</manifest>
I am launching my first service in MainActivity on Button click as:
MainActivity.java
public class MainActivity extends ActionBarActivity implements OnClickListener {
private Button mLanchServiceBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLanchServiceBtn=(Button) findViewById(R.id.launch_btn);
mLanchServiceBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
//Starting first service
Intent launch=new Intent(this,FirstService.class);
startService(launch);
}
}
And second service in MainApplication class as.
MainApplication.java
public class MainApplication extends Application {
private SecondService.LocalBinder mBinder;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = (LocalBinder) service;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
#Override
public void onCreate() {
super.onCreate();
//starting second service
Intent launch=new Intent(this,SecondService.class);
startService(launch);
//Binding to it
bindService(launch, mConnection, BIND_AUTO_CREATE);
}
}
FirstService.java
public class FirstService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
SecondService.java
public class SecondService extends Service{
//Service Containing Local Binder
private LocalBinder mBinder=new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class LocalBinder extends Binder{
public LocalBinder() {
}
}
}
StackTrace:
02-05 10:32:25.035: E/AndroidRuntime(1424): Process:
com.service.check:newProcess, PID: 1424 02-05 10:32:25.035:
E/AndroidRuntime(1424): java.lang.ClassCastException:
android.os.BinderProxy cannot be cast to
com.service.check.SecondService$LocalBinder 02-05 10:32:25.035:
E/AndroidRuntime(1424): at
com.service.check.MainApplication$1.onServiceConnected(MainApplication.java:23)
02-05 10:32:25.035: E/AndroidRuntime(1424): at
android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1101)
I have referred the following links to sort out the issue which says,
if my activity and service are in separate processes then we should not bind the way I have done.
Android service android.os.BinderProxy error
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to LocalBinder
But in my case:
I am binding to SecondService from MainApplication and both are running in same Process(i.e Default Application Process). Still I am facing binderProxy exception in SecondService , And my FirstService runs in separate process which I am not even binding to.
Please help me out with this situation and, Suggest me a best possible way so that I can implement same scenario without any crash.
Ran into this issue (local service returning a BinderProxy), wanted to post what I'd found since I found this page while trying to debug. The short version as a run on sentence: starting a remote service creates a second instance of your Application class in a new process which then tries to bind to the local service that was started by the original Application instance as if it was a local service but since the service is running in the original process it's binding across processes and you get a BinderProxy instead of your expected Binder class.
There's a few things to keep in mind about Android services. Every service has an assigned process it will run in. If you don't assign a process in your Android Manifest it will run in the default process (the process where the Application, Activities, etc are run). Not giving a process name doesn't mean that it will run the service in the same process that you're binding to/starting the service from.
Let's say I have a MyApplication class which attempts to bind to two services on start up: one service running in the default process (we'll call this the LocalService), one running in a separate process (the RemoteService).
The user launches my app which creates a MyApplication instance in the default process. This instance then tries to bind to the LocalService. Android creates the LocalService in the default process and returns the LocalService's Binder class to the app (mBinder = (LocalBinder) service;). That's all good, we've successfully bound to the LocalService.
Next the app tries to bind to the RemoteService. Android creates a new process with the name you've supplied in the Android Manifest. However, before it can create the RemoteService it needs to create an Application for the service to run in. It creates a new MyApplication instance in the remote process and starts that up.
However, that new MyApplication instance running in a separate process tries to bind to the LocalService during start up. Because the LocalService is running in the default process this is a cross process binding but MyApplication expects this to be an in process binding. Android returns a BinderProxy, the second MyApplication instance tries to cast it to a LocalBinder and crashes. The fun part is that it crashes in a different process so your app and activity can actually continue running. You'll just never be able to bind to the remote service.
If you want to bind to a local service with an Application context and also use a remote service you'll need to handle the fact that Android will create another Application in the remote process when starting the remote service. I haven't bothered to try this (I just made my remote service a local service), but you could probably check the process name during the application's on create and not bind if it's not the default process.
Found an answer after doing some research and debugging,
If we create and bind any service to a MainApplication class(then service gets binded to whole ApplicationContext or BaseContext) and if same application contains other services which are binded to Activity specific Context(s),
//Declared in MainApplication
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = (LocalBinder) service;
}
In OnServiceConnected() We will get binder object for both the Services( SecondService Started in MainApplication(registered with BaseContext will get local binderObject) class and FirstService started MainActivity(will get android.os.binderProxyObject hence causing ClassCastException).
So, to fix this issue one has to start all the application
services from any Activity Context rather than using any Global
Application Context. Also this issue is independent of the
Processes
Hence, I moved both SecondService and FirstService into MainActivity
Context which fixed the issue.
MainActivity.java
private Button mLanchServiceBtn;
private SecondService.LocalBinder mBinder;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = (LocalBinder) service;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLanchServiceBtn=(Button) findViewById(R.id.launch_btn);
mLanchServiceBtn.setOnClickListener(this);
//starting second service in activity
Intent launch=new Intent(this,SecondService.class);
startService(launch);
//Binding to it
bindService(launch, mConnection, BIND_AUTO_CREATE);
}
#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;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
//Starting FirstService also from MainActivity
Intent launch=new Intent(this,FirstService.class);
startService(launch);
}
}
You can't call directly any methods of your remote services (or cast) because they live in different process so you can't get a reference to it's instance. But Android has specific interfaces to handle this interprocess communications (IPC). The easiest way is using android.os.Messenger (another is AIDL, more complex).
On your Service, your implementation of Service#onBind() will be a little bit different:
override fun onBind(intent: Intent): IBinder? {
mMessenger = Messenger(YourServiceHandler())
return mMessenger.binder
}
And on your Activity implementation of ServiceConnection#onServiceConnected(serviceBinder: IBinder) you will not get a directly reference to your remote service instance, but instead create a Messenger that have a send(message: Message) interface so you can remotelly call the service functions:
override fun onServiceConnected(className: ComponentName, service: IBinder) {
mServiceMessenger = Messenger(service)
}
override fun onCreate(){
doStuff1Button.setOnClickListener{
val msg = Message.obtain(null, YourRemoteService.MESSAGE_DO_STUFF_1, 0, 0)
mServiceMessenger.send(msg)
}
doStuff1Button.setOnClickListener{
val msg = Message.obtain(null, YourRemoteService.MESSAGE_DO_STUFF_2, 0, 0)
mServiceMessenger.send(msg)
}
}
Note that in the message is going a argument do stuff 1 or 2. You will get this back on your service handler Handler#onHandleMessage(message: Message) with the attribute what:
override fun handleMessage(message: Message) {
when (message.what) {
MESSAGE_DO_STUFF_1 -> doStuff1()
MESSAGE_DO_STUFF_2 -> doStuff2()
}
}
Complete guide can be found in this official documentation
I tried above all solutions but none of those worked. If anyone was stuck same as myself try this based on #Coeffect answer. In my scenario service clients doesn't belong to my current application(process)
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBinder = LocalBinder.Stub.asInterface(service);
}
I have a problem with a BroadcastReceiver. If I declare the action in the manifest in this way:
<receiver android:name="com.app.activity.observer.DataEntryObserver" >
<intent-filter>
<action android:name= "#string/action_db_updated" />
</intent-filter>
</receiver>
where in the strings.xml I have:
<string name="action_db_updated">com.app.DB_UPDATED</string>
everything works well. But if I change it to:
<receiver android:name="com.app.activity.observer.DataEntryObserver" >
<intent-filter>
<action android:name= "com.app.DB_UPDATED" />
</intent-filter>
</receiver>
I have this exception as the receiver is called:
java.lang.RuntimeException: Unable to instantiate receiver com.app.activity.observer.DataEntryObserver: java.lang.InstantiationException: can't instantiate class com.app.activity.observer.DataEntryObserver; no empty constructor
I would keep the working version but the Play store doesn't allow me to publish the app because it expects a string value and not a variable #string/..
my receiver is an outerclass and is defined as:
public class DataEntryObserver extends BroadcastReceiver{
private AppUsageLoader dLoader;
public DataEntryObserver(AppUsageLoader dLoader) {
this.dLoader = dLoader;
IntentFilter filter = new IntentFilter(
ReaLifeApplication.ACTION_DB_UPDATED);
dLoader.getContext().registerReceiver(this, filter);
}
#Override
public void onReceive(Context arg0, Intent arg1) {
// Tell the loader about the change.
dLoader.onContentChanged();
}
}
Make the class a static class, otherwise it's "seen" as part of the original containing class instance.
thus:
public static class DataEntryObserver extends BroadcastReceiver{
public DeviceAdminSampleReceiver() {
super();
}
...
https://stackoverflow.com/a/10305338/1285325
You need an empty constructor like this:
public class DataEntryObserver extends BroadcastReceiver{
private AppUsageLoader dLoader;
// Empty constructor
public DataEntryObserver() { }
public DataEntryObserver(AppUsageLoader dLoader) {
this.dLoader = dLoader;
IntentFilter filter = new IntentFilter(
ReaLifeApplication.ACTION_DB_UPDATED);
dLoader.getContext().registerReceiver(this, filter);
}
#Override
public void onReceive(Context arg0, Intent arg1) {
// Tell the loader about the change.
dLoader.onContentChanged();
}
}
Although I'm not sure if keeping the non-empty constructor will generate the same error. If it does, you will have to remove it.
need to empty constructor
public DataEntryObserver() {
this.dLoader = null;
}
Instead of dynamic registration, I want to statically register my receiver.
For dynamic registration, it works well, I was using this :
..
static private IntentFilter GPSActionFilter;
..
GPSActionFilter = new IntentFilter("GGPS Service");
context.registerReceiver(GPSActionReceiver, GPSActionFilter);
..
static private BroadcastReceiver GPSActionReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) { ..}
For static registration, debugger never hits the onReceive function, I am using this:
In AndoridManifest :
<receiver android:name="LocationListener$GPSActionReceiver" >
<intent-filter>
<action android:name="LocationListener.ACTION_GPS_SERVICE" />
</intent-filter>
</receiver>
In code :
public class LocationListener extends BroadcastReceiver
{
public static IntentFilter GPSActionFilter;
public static final String ACTION_GPS_SERVICE = "com.example.LocationListener.GPSActionFilter";
public static BroadcastReceiver GPSActionReceiver;
public void onReceive(final Context context, final Intent intent)
{..}
}
When declaring an intent-filter action in the manifest, the android:name must be a string literal and can not access Strings from classes. Also, I recommend you prepend your fully qualified package name to the intent action ie:
public static final String GPS_SERVICE = "com.example.LocationListener.ACTION_GPS_SERVICE"
Then change
<action android:name="LocationListener.GPS_SERVICE" />
To
<action android:name="com.example.LocationListener.ACTION_GPS_SERVICE" />
First, you cannot have a private BroadcastReceiver in the manifest, as Android needs to be able to create an instance of it. Please make this public.
Second, the syntax for the name of static inner classes is LocationListener$GPSActionReceiver, not LocationListener.GPSActionReceiver.