如何以正确的方式在服务和它的应用程序之间传递数据?

时间:2012-02-13 08:06:11

标签: android android-intent chat android-service android-asynctask

我是android的新手。在我的应用程序中,我创建了一个多对多聊天,并需要从服务器更新消息列表。为了做到这一点,我创建了一个服务,每秒从服务器更新。

我的问题是我不知道如何将数据传回给应用程序。我知道我应该使用意图和广播接收器,但是我坚持使用Bundle对象,我必须序列化以便将它传递给应用程序,这对我来说没有意义,因为这个操作不是那个高效。

现在我正在使用我的应用程序的参考(我认为它不是那么好,但不知道为什么),并且在服务中的服务器每次更新后我都会激活应用程序功能,并直接更新它的字段。此外,我想也许我的代码也会对初学者有所帮助:))

public class UpdateChatService extends Service {

private static final long DELAY_FOR_CHAT_TASK = 0;
private static final long PERIOD_FOR_CHAT_TASK = 1;
private static final TimeUnit TIME_UNIT_CHAT_TASK = TimeUnit.SECONDS;

//private Task retryTask; TODO: check this out
private ScheduledExecutorService scheduler;

private boolean timerRunning = false;
private long RETRY_TIME = 200000;
private long START_TIME = 5000;

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

@Override
public void onCreate() {
    super.onCreate();

    scheduleChatUpdate();
}

private void scheduleChatUpdate() {
    BiggerGameApp app = (BiggerGameApp) getApplication();
    this.scheduler = Executors.newScheduledThreadPool(3);
    this.scheduler.scheduleAtFixedRate(new UpdateChatTask(app), 
            DELAY_FOR_CHAT_TASK, PERIOD_FOR_CHAT_TASK,
            TIME_UNIT_CHAT_TASK);
    timerRunning = true;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (!timerRunning) {
        scheduleChatUpdate();
    }

    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
    super.onDestroy();

    if (scheduler != null) {
        scheduler.shutdown();
    }

    timerRunning = false;
}

}

以下是服务中运行的异步任务的代码。 请告诉我我做错了什么,以及如何将数据从服务传递到应用程序。

public void run() {
    try {
        if (this.app.getLastMsgFromServer() == null) {
            this.app.setLastMsgFromServer(new Message(new Player(DEFAULT_EMAIL), "", -1));
            this.app.getLastMsgFromServer().setMessageId(-1);
        }

        Gson gson = new GsonBuilder()
        .registerTypeAdapter(DateTime.class, new DateTimeTypeConverter())
        .create();
        ServerHandler serverHandler = new ServerHandler();

        String jsonString = gson.toJson(this.app.getLastMsgFromServer());

        // Sending player to servlet in server
        String resultString = serverHandler.getResultFromServlet(jsonString, "GetListOfMessages");      

        if (resultString.contains("Error")) {
            return;
        }

        // Parsing answer
        JSONObject json = new JSONObject(resultString);
        Status status = null;
        String statusString = json.getString("status");    

        if (statusString == null || statusString.length() == 0)
            return;

        status = Status.valueOf(statusString);

        if (Status.SUCCESS.equals(status)) {       
            ArrayList<Message> tempChat = null;

            JSONArray jsonList = json.getJSONArray("data");
            MyJsonParser jsonParser = new MyJsonParser();
            tempChat = jsonParser.getListOfMessagesFromJson(jsonList.toString());    

            if (tempChat != null && tempChat.size() != 0) {
                // After getting the chat from the server, it saves the last msg
                // For next syncing with the server
                this.app.setLastMsgFromServer(tempChat.get(LAST_MSG_INDEX));

                tempChat.addAll(this.app.getChat());

                if (tempChat.size() > SIZE_OF_USER_CHAT) {
                    tempChat = (ArrayList<Message>) tempChat.subList(0, SIZE_OF_USER_CHAT - 1);
                }

                this.app.setChat(tempChat);
                this.app.updateViews(null);
            }
        }

        return;

3 个答案:

答案 0 :(得分:2)

服务是否仅限本地(我将假设“是”)?

通过传递android.os.Binder的实例,可以完成与本地服务的通信,如下所示:

public class UpdateChatService extends Service {
    public static final class UpdateChat extends Binder {
        UpdateChatService mInstance;
        UpdateChat(UpdateChatService instance) {
            mInstance = instance;
        }

        public static UpdateChat asUpdateChat(IBinder binder) {
            if (binder instanceof UpdateChat) {
                return (UpdateChat) binder;
            }
            return null;
        }

        public String pollMessage() {
            // Takes a message from the list or returns null
            // if the list is empty.
            return mInstance.mMessages.poll();
        }

        public void registerDataSetObserver(DataSetObserver observer) {
            mInstance.mObservable.registerObserver(observer);
        }

        public void unregisterDataSetObserver(DataSetObserver observer) {
            mInstance.mObservable.unregisterObserver(observer);
        }
    }

    private ScheduledExecutorService mScheduler;
    private LinkedList<String> mMessages;
    private DataSetObservable mObservable;

    @Override
    public IBinder onBind(Intent intent) {
        return new UpdateChat(this);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mObservable = new DataSetObservable();
        mMessages = new LinkedList<String>();
        mScheduler = Executors.newScheduledThreadPool(3);
        mScheduler.scheduleAtFixedRate(new UpdateChatTask(), 0, 1, TimeUnit.SECONDS);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mScheduler.shutdownNow();
        mObservable.notifyInvalidated();
    }

    class UpdateChatTask implements Runnable {
        int mN = 0;
        public void run() {
            // This example uses a list to keep all received messages, your requirements may vary.
            mMessages.add("Message #" + (++mN));
            mObservable.notifyChanged();
        }
    }
}

此示例可用于向Activity(在这种情况下为ListActivity)提供,如下所示:

public class ChattrActivity extends ListActivity implements ServiceConnection {
    LinkedList<String> mMessages;
    ArrayAdapter<String> mAdapter;
    UpdateChat mUpdateChat;
    DataSetObserver mObserver;
    Runnable mNotify;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMessages = new LinkedList<String>();
        mNotify = new Runnable() {
            public void run() {
                mAdapter.notifyDataSetChanged();
            }
        };
        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mMessages);
        getListView().setAdapter(mAdapter);
        // Bind to the Service if you do not need it to persist when this Activity
        // dies - otherwise you must call #startService(..) before!
        bindService(new Intent(this, UpdateChatService.class), this, BIND_AUTO_CREATE);
    }

    /**
     * @see android.app.ListActivity#onDestroy()
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mUpdateChat != null) {
            mUpdateChat.unregisterDataSetObserver(mObserver);
            unbindService(this);
        }
    }

    public void onServiceConnected(ComponentName name, IBinder service) {
        mUpdateChat = UpdateChat.asUpdateChat(service);
        mObserver = new DataSetObserver() {
            @Override
            public void onChanged() {
                String message;
                while ((message = mUpdateChat.pollMessage()) != null) {
                    mMessages.add(message);
                }
                runOnUiThread(mNotify);
            }
            @Override
            public void onInvalidated() {
                // Service was killed - restart or handle this error somehow.
            }
        };
        // We use a DataSetObserver to notify us when a message has been "received".
        mUpdateChat.registerDataSetObserver(mObserver);
    }

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

如果您需要跨进程进行通信,则应考虑实现AIDL接口 - 但对于“本地”版本,此模式可以正常工作。不涉及滥用全局Application实例。

答案 1 :(得分:0)

您可以使用服务与其他应用程序(活动)之间共享的静态内存。如果您不打算将此服务公开给外部应用程序,那么共享静态内存比通过bundle序列化/反序列化数据更好。

鼓励基于捆绑的方法用于暴露于外部世界的组件。典型的应用程序通常只有应用程序清单文件中公开的主要活动。

答案 2 :(得分:0)

如果你的服务没有用,那么静态内存和回调功能都可以。 如果没有,您可以发送广播。