ServiceConnection.onServiceConnected()绑定到开始服务之后,从来没有所谓的 [英] ServiceConnection.onServiceConnected() never called after binding to started service

查看:137
本文介绍了ServiceConnection.onServiceConnected()绑定到开始服务之后,从来没有所谓的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在游戏应用我有以下情形:

  • 从主游戏活动,播放器开始,在与时间长短不一后台运行多个游戏任务。
  • 玩家应该能够查看在一个单独的查看的运行游戏的任务的进度。

要做到这一点,我创建了两个活动和一个服务,定义如下:

  • 服务ProgressService 处理几个进度 S上并行线程同时运行。

  • 活动WorkScreen2 创建一个游戏任务,启动服务 startService ()在传递任务参数捆绑

  • 活动ProgressScreen 绑定到服务来获取和显示进度 S的正在运行的任务。

  • 在单独运行这两项活动 TabHost 取值一个 TabActivity


我遇到的问题是, ServiceConnection.onServiceConnected()方法不会被调用。我得到一个显示java.lang.NullPointerException ,因为我尝试调用服务对象应在指定的方法此方法。见下面code。

我用 getApplicationContext()。bindService()绑定活动服务,因为 则tabspec 无法绑定到服务 。这个方法返回。因此,绑定成功


下面是服务

公共类ProgressService扩展服务实现GameConstants {     公共静态最后弦乐BROADCAST_PROGRESS =com.mycompany.android.mygame.progressbroadcast;     私有静态最后长的更新周期= 500;     私人的IBinder mBinder;     私人名单,其中,进度> mProgressBarList;     私人列表<字符串> mStaffNameList;     私人final类ServiceHandler扩展处理程序{         公共ServiceHandler(活套活套){             超(活套);         }         @覆盖         公共无效的handleMessage(信息MSG){             进度进度=新进度(ProgressService.this);             mProgressBarList.add(进度);             束束= msg.getData();             字符串staffName = bundle.getString(WorkScreen2.STAFF_NAME);             mStaffNameList.add(staffName);             INT taskDurationMillis = bundle.getInt(WorkScreen2.TASK_DURATION)* 1000;             progressBar.setMax(taskDurationMillis / 1000);             长startTimeMillis = SystemClock.uptimeMillis();             长ela​​psedTimeMillis = SystemClock.uptimeMillis()                      - startTimeMillis;             意向意图=新的意图();             intent.setAction(BROADCAST_PROGRESS);             而(elapsedTimeMillis< taskDurationMillis){                 尝试 {                     视频下载(更新周期​​);                 }赶上(InterruptedException异常E){                     e.printStackTrace();                 }                 elapsedTimeMillis = SystemClock.uptimeMillis()                          - startTimeMillis;                 INT elapsedTimeSeconds =(int)的elapsedTimeMillis / 1000;                 progressBar.setProgress(elapsedTimeSeconds);                 sendBroadcast(意向);             }             progressBar.setVisibility(View.GONE);             mProgressBarList.remove(进度);             mStaffNameList.remove(staffName);             sendBroadcast(意向);             如果(mProgressBarList.isEmpty()){                 stopSelf(msg.arg1);             }         }     }     @覆盖     公共无效的onCreate(){         super.onCreate();         mBinder =新ProgressServiceBinder();         mProgressBarList =集合                 .synchronizedList(新的ArrayList&其中;进度>());         mStaffNameList = Collections.synchronizedList(新的ArrayList&其中;字符串>());     }     / *      *创建每场比赛的任务一个线程在传递的参数      *< code>的意图< / code取代;      * /     @覆盖     公众诠释onStartCommand(意向意图,诠释标志,诠释startId){         Toast.makeText(这一点,启动服务,Toast.LENGTH_LONG).show();         HandlerThread线程=新HandlerThread(ServiceStartArguments                 Process.THREAD_PRIORITY_BACKGROUND);         thread.start();         处理器serviceHandler =新ServiceHandler(thread.getLooper());         消息味精= serviceHandler.obtainMessage();         msg.arg1 = startId;         msg.setData(intent.getExtras());         serviceHandler.sendMessage(MSG);         返回START_STICKY;     }     @覆盖     公众的IBinder onBind(意向意图){         返回mBinder;     }     公共类ProgressServiceBinder扩展粘合剂{         ProgressService的getService(){             返回ProgressService.this;         }     }     公开名单<进度> getProgressBarList(){         返回mProgressBarList;     }     公开名单<字符串> getStaffNameList(){         返回mStaffNameList;     }     @覆盖     公共无效的onDestroy(){         Toast.makeText(这一点,做服务,Toast.LENGTH_SHORT).show();     } }

这是活动绑定到它:

公共类ProgressScreen扩展ListActivity {     私人最终字符串变量=ProgressScreen;     私人ProgressScreenAdapter mAdapter;     私人ProgressService mProgressService;     私人名单,其中,进度> mProgressBarList;     私人列表<字符串> mStaffNameList;     @覆盖     公共无效的onCreate(束捆){         Log.i(TAG,ProgressScreen的OnCreate);         super.onCreate(包);         的setContentView(R.layout.progress_screen_layout);         IntentFilter的过滤器=新的IntentFilter();         filter.addAction(ProgressService.BROADCAST_PROGRESS);         registerReceiver(接收机,过滤器);         doBindService();         mAdapter =新ProgressScreenAdapter(这一点,mStaffNameList,mProgressBarList);         setListAdapter(mAdapter); //返回true         / *          *这是我得到的NullPointerException异常          * mProgressService为null这里          * /         mProgressBarList = mProgressService.getProgressBarList();         mStaffNameList = mProgressService.getStaffNameList();     }     @覆盖     保护无效onResume(){         super.onResume();         IntentFilter的过滤器=新的IntentFilter();         filter.addAction(ProgressService.BROADCAST_PROGRESS);         registerReceiver(接收机,过滤器);     }     @覆盖     保护无效的onPause(){         super.onPause();         unregisterReceiver(接收机);     }     布尔doBindService(){         。返回getApplicationContext()bindService(新意图(这一点,ProgressService.class),mConnection,Context.BIND_AUTO_CREATE);     }     无效doUnbindService(){         。getApplicationContext()unbindService(mConnection);     }     ServiceConnection mConnection =新ServiceConnection(){         公共无效onServiceConnected(组件名的className,粘合剂的IBinder){             mProgressService =((ProgressService.ProgressServiceBinder)粘合剂).getService();             Toast.makeText(ProgressScreen.this,连接到ProgressService,Toast.LENGTH_SHORT).show();         }         公共无效onServiceDisconnected(组件名名){             mProgressService = NULL;         }     };     私人BroadcastReceiver的接收器=新的BroadcastReceiver(){         @覆盖         公共无效的onReceive(上下文的背景下,意图意图){             mAdapter.notifyDataSetChanged();         }     }; }

服务从主活动开始如下:

意向意图=新的意图(WorkScreen2.this,ProgressService.class); intent.putExtra(TASK_DURATION,task.getDuration()); intent.putExtra(STAFF_NAME,staff.getName()); startService(意向);

的Andr​​oidManifest.xml 包含

 <服务
    机器人:名称=。ProgressService
    机器人:标签=@字符串/ progress_service>
< /服务>
 

解决方案

ServiceConnection的onServiceConnected(),但没有人可以保证,这将是一个名为之前的onCreate继续执行。因此,这里发生的事情 - 你successfuly绑定到该服务(这就是为什么onBind返回true),但是你不能的完全连接的 - onServiceConnected()尚未被调用,所以当地的mProgressService对象尚未initalized,所以你得到的NullPointerException异常。

解决方法:

将以下两行:

  mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();
 

从的onCreate()来onServiceConnected()函数(使用服务对象的它是在onServiceConnected初始化())。

In a game application I have the following scenario:

  • From the main game Activity, the player starts several game tasks that run in the background with varying duration.
  • The player should be able to view the progress of the running game tasks in a separate View.

To do this, I created two Activitys and a Service, defined as follows:

  • Service ProgressService handles several ProgressBars running simultaneously on parallel threads.

  • Activity WorkScreen2 creates a game task, starts the Service with startService() with task parameters passed in a Bundle.

  • Activity ProgressScreen binds to the Service to get and display the ProgressBars of the running tasks.

  • Both activities run under separate TabHosts of one TabActivity.


The problem I'm having is that the ServiceConnection.onServiceConnected() method is never called. I get a Java.lang.NullPointerException because I try to call a method of the Service object that should be assigned in this method. See code below.

I use getApplicationContext().bindService() to bind the Activity to the Service because TabSpec cannot bind to Services. This method returns true. Therefore, binding is successful.


Here is the Service:

public class ProgressService extends Service implements GameConstants {
    public static final String BROADCAST_PROGRESS = "com.mycompany.android.mygame.progressbroadcast";
    private static final long UPDATE_INTERVAL = 500;
    private IBinder mBinder;
    private List<ProgressBar> mProgressBarList;
    private List<String> mStaffNameList;

    private final class ServiceHandler extends Handler {

        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            ProgressBar progressBar = new ProgressBar(ProgressService.this);
            mProgressBarList.add(progressBar);

            Bundle bundle = msg.getData();
            String staffName = bundle.getString(WorkScreen2.STAFF_NAME);
            mStaffNameList.add(staffName);

            int taskDurationMillis = bundle.getInt(WorkScreen2.TASK_DURATION) * 1000;
            progressBar.setMax(taskDurationMillis / 1000);

            long startTimeMillis = SystemClock.uptimeMillis();
            long elapsedTimeMillis = SystemClock.uptimeMillis()
                    - startTimeMillis;

            Intent intent = new Intent();
            intent.setAction(BROADCAST_PROGRESS);

            while (elapsedTimeMillis < taskDurationMillis) {
                try {
                    Thread.sleep(UPDATE_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                elapsedTimeMillis = SystemClock.uptimeMillis()
                        - startTimeMillis;
                int elapsedTimeSeconds = (int) elapsedTimeMillis / 1000;
                progressBar.setProgress(elapsedTimeSeconds);
                sendBroadcast(intent);
            }

            progressBar.setVisibility(View.GONE);
            mProgressBarList.remove(progressBar);
            mStaffNameList.remove(staffName);
            sendBroadcast(intent);

            if (mProgressBarList.isEmpty()) {
                stopSelf(msg.arg1);
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new ProgressServiceBinder();
        mProgressBarList = Collections
                .synchronizedList(new ArrayList<ProgressBar>());
        mStaffNameList = Collections.synchronizedList(new ArrayList<String>());
    }

    /*
     * Creates a thread for each game task with parameters passed in
     * <code>intent</code>
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "starting service", Toast.LENGTH_LONG).show();

        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();

        Handler serviceHandler = new ServiceHandler(thread.getLooper());

        Message msg = serviceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.setData(intent.getExtras());
        serviceHandler.sendMessage(msg);

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class ProgressServiceBinder extends Binder {
        ProgressService getService() {
            return ProgressService.this;
        }
    }

    public List<ProgressBar> getProgressBarList() {
        return mProgressBarList;
    }

    public List<String> getStaffNameList() {
        return mStaffNameList;
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "Service done", Toast.LENGTH_SHORT).show();
    }
}

And this is the Activity that binds to it:

public class ProgressScreen extends ListActivity {
    private final String TAG = "ProgressScreen";

    private ProgressScreenAdapter mAdapter;
    private ProgressService mProgressService;
    private List<ProgressBar> mProgressBarList;
    private List<String> mStaffNameList;

    @Override
    public void onCreate(Bundle bundle) {
        Log.i(TAG, "ProgressScreen oncreate");

        super.onCreate(bundle);
        setContentView(R.layout.progress_screen_layout);
        IntentFilter filter = new IntentFilter();
        filter.addAction(ProgressService.BROADCAST_PROGRESS);
        registerReceiver(receiver, filter);
        doBindService();

        mAdapter = new ProgressScreenAdapter(this, mStaffNameList, mProgressBarList);
        setListAdapter(mAdapter); // Returns true

        /*
         * This is where I get the NullPointerException
         * mProgressService is null here
         */
        mProgressBarList = mProgressService.getProgressBarList();
        mStaffNameList = mProgressService.getStaffNameList();
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ProgressService.BROADCAST_PROGRESS);
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

    boolean doBindService() {
        return getApplicationContext().bindService(new Intent(this, ProgressService.class), mConnection, Context.BIND_AUTO_CREATE);
    }

    void doUnbindService() {
        getApplicationContext().unbindService(mConnection);
    }

    ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className, IBinder binder) {
            mProgressService = ((ProgressService.ProgressServiceBinder) binder).getService();
            Toast.makeText(ProgressScreen.this, "Connected to ProgressService", Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName name) {
            mProgressService = null;
        }
    };

    private BroadcastReceiver receiver = new BroadcastReceiver () {
        @Override
        public void onReceive(Context context, Intent intent) {
            mAdapter.notifyDataSetChanged();
        }
    };
}

And the Service is started from the main Activity as follows:

Intent intent = new Intent(WorkScreen2.this, ProgressService.class);
intent.putExtra(TASK_DURATION, task.getDuration());
intent.putExtra(STAFF_NAME, staff.getName());
startService(intent);

The AndroidManifest.xml contains

<service
    android:name=".ProgressService"
    android:label="@string/progress_service">
</service>

解决方案

ServiceConnection's onServiceConnected() is called, but nobody guarantees that it will be called before onCreate continues execution. So, what happens here - you successfuly bind to the service (that's why onBind returns true), but you're not fully connected - onServiceConnected() has not yet been called, so your local mProgressService object is not yet initalized, and therefore you get the NullPointerException.

Solution:

Move these two lines:

mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();

from onCreate() to onServiceConnected() function (use the service object after it is initialized in onServiceConnected()).

这篇关于ServiceConnection.onServiceConnected()绑定到开始服务之后,从来没有所谓的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆