Android在片段和服务之间发送消息

Android在片段和服务之间发送消息,第1张

概述我有一个带有按钮的片段.单击时,它告诉服务开始轮询传感器,然后将传感器数据插入后台线程的数据库中.当再次按下按钮时,服务将停止.当按下“停止”按钮时,执行者队列中仍可能有一些任务正在插入到数据库中,因此在此期间,我想显示一个进度对话框,并在清除整个队列后将其关闭.带按钮

我有一个带有按钮的片段.单击时,它告诉服务开始轮询传感器,然后将传感器数据插入后台线程的数据库中.当再次按下按钮时,服务将停止.当按下“停止”按钮时,执行者队列中仍可能有一些任务正在插入到数据库中,因此在此期间,我想显示一个进度对话框,并在清除整个队列后将其关闭.带按钮的片段如下所示:

public class StartFragment extends Fragment implements VIEw.OnClickListener {    button startbutton;    @OverrIDe    public VIEw onCreateVIEw(LayoutInflater inflater, VIEwGroup container,                             Bundle savedInstanceState) {        VIEw vIEw = inflater.inflate(R.layout.fragment_start, container, false);        startbutton = (button) vIEw.findVIEwByID(R.ID.startbutton);        startbutton.setonClickListener(this);        return vIEw;    }    @OverrIDe    public voID onClick(VIEw v) {        if (recording has not yet started){             mainActivity.startService(new Intent(mainActivity, SensorService.class));        } else {            //I want to display a progress dialog here when the service is told to stop            //Once all executor task queue is clear, I want to dismiss this dialog            mainActivity.stopService(new Intent(mainActivity, SensorService.class));        }    }}

首次单击该按钮时,将启动以下服务:

public class SensorService extends Service implements SensorEventListener {    public static final int SCREEN_OFF_RECEIVER_DELAY = 100;    private SensorManager sensorManager = null;    private WakeLock wakeLock = null;    ExecutorService executor;    Runnable insertHandler;    private voID registerListener() {        //register 4 sensor Listeners (acceleration, gyro, magnetic, gravity)    }    private voID unregisterListener() {        sensorManager.unregisterListener(this);    }    public broadcastReceiver receiver = new broadcastReceiver() {        @OverrIDe        public voID onReceive(Context context, Intent intent) {            Log.i(TAG, "onReceive("+intent+")");            if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {                return;            }            Runnable runnable = new Runnable() {                public voID run() {                    Log.i(TAG, "Runnable executing...");                    unregisterListener();                    registerListener();                }            };            new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);        }    };    public voID onSensorChanged(SensorEvent event) {        //get sensor values and store into 4 different arrays here        //insert into database in background thread        executor.execute(insertHandler);    }    @OverrIDe    public voID onCreate() {        super.onCreate();        //get sensor manager and sensors here        PowerManager manager = (PowerManager) getSystemService(Context.POWER_SERVICE);        wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);        registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));        //Executor service and runnable for DB inserts        executor = Executors.newSingleThreadExecutor();        insertHandler = new InsertHandler();    }    @OverrIDe    public IBinder onBind(Intent intent) {        return null;    }    @OverrIDe    public int onStartCommand(Intent intent, int flags, int startID) {        super.onStartCommand(intent, flags, startID);        startForeground(Process.myPID(), new Notification());        registerListener();        wakeLock.acquire();        return START_STICKY;    }    @OverrIDe    public voID onDestroy() {        //Prevent new tasks from being added to thread        executor.shutdown();        try {            //Wait for all tasks to finish before we proceed            while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {                Log.i(TAG, "Waiting for current tasks to finish");            }        } catch (InterruptedException e) {            executor.shutdownNow();            Thread.currentThread().interrupt();        }        if (executor.isTerminated()){            //Stop everything else once the task queue is clear            unregisterReceiver(receiver);            unregisterListener();            wakeLock.release();            dbHelper.close();            stopForeground(true);            //Once the queue is clear, I want to send a message back to the fragment to dismiss the progress dialog here        }    }    class InsertHandler implements Runnable {        public voID run() {            //get sensor values from 4 arrays, and insert into db here    }}

所以我想在按下第二个按钮时显示对话框.然后,一旦再次按下它,服务将停止,我要等到队列清除后再将dismiss事件发送回片段以关闭进度对话框.

显示对话框很容易.我可以在调用stopService之前,在片段的onClick方法中添加进度对话框代码

我在弄清楚如何在SensorService的onDestroy中发送消息以关闭该对话框时遇到了困难

在不借助外部库的情况下实现此目的的最佳方法是什么?

是否可以使用某种方式使用我在SensorService中使用的broadcastReceiver?还是最好在片段中创建一个新的Handler,然后以某种方式将其传递给服务,以便它可以将消息发送回片段?

编辑:

我已经根据以下答案之一尝试了以下方法:

在我的片段类中添加了MessageHandler类:

public static class MessageHandler extends Handler {    @OverrIDe    public voID handleMessage(Message message) {        int state = message.arg1;        switch (state) {            case 0:                stopDialog.dismiss();                break;            case 1:                stopDialog = new ProgressDialog(mainActivity);                stopDialog.setMessage("StopPing...");                stopDialog.setTitle("Saving data");                stopDialog.setProgressNumberFormat(null);                stopDialog.setCancelable(false);                stopDialog.setMax(100);                stopDialog.show();                break;        }    }}

在我的片段中创建了一个新的MessageHandler实例(试图将其放置在多个位置…结果相同):

public static Handler messageHandler = new MessageHandler();

然后使用以下命令从我的片段启动服务:

Intent startService = new Intent(mainActivity, SensorService.class);startService.putExtra("MESSENGER", new Messenger(messageHandler));getContext().startService(startService);

在我的SensorService broadcastReceiver中,创建messageHandler:

Bundle extras = intent.getExtras();messageHandler = (Messenger) extras.get("MESSENGER");

然后,在SensorService onDestroy的最开始显示对话框:

sendMessage("SHOW");

并在同一方法的最后将其关闭:

sendMessage("HIDE");

我的sendMessage方法看起来像这样:

public voID sendMessage(String state) {        Message message = Message.obtain();        switch (state) {            case "SHOW":                message.arg1 = 1;                break;            case "HIDE" :                message.arg1 = 0;                break;        }        try {            messageHandler.send(message);        } catch (remoteexception e) {            e.printstacktrace();        }    }

这样我就可以启动“服务正常”了,但是当我再次按它停止时,我得到了:

java.lang.RuntimeException:无法停止服务com.example.app.SensorService@21124f0:java.lang.NullPointerException:尝试在虚拟设备上调用虚拟方法’voID androID.os.Messenger.send(androID.os.Message)’空对象引用

及其涉及SensorService.send(message)的SensorService的第105行

关于什么可能是错的想法?

解决方法:

活动中:

protected broadcastReceiver mMessageReceiver = new broadcastReceiver() {    @OverrIDe    public voID onReceive(Context context, final Intent intent) {        runOnUiThread(new Runnable() {            @OverrIDe            public voID run() {                if(intent.hasExtra("someExtraMessage")){                    doSomething(intent.getStringExtra("someExtraMessage"));                }            }        });    }};@OverrIDepublic voID onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {    super.onCreate(savedInstanceState, persistentState);    LocalbroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,            new IntentFilter("message-ID"));}protected voID onDestroy() {    super.onDestroy();    LocalbroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);}public voID doSomething(){    //...}

然后从服务的某个地方:

Context context = BamBamApplication.getApplicationContext(); // Can be application or activity context.// BamBamApplicaiton extends Application ;)Intent intent = new Intent("message-ID");intent.putExtra("someExtraMessage", "Some Message :)");LocalbroadcastManager.getInstance(context).sendbroadcast(intent);

实际上,您从一开始就做错了:)所有服务都在主线程上运行,因此在这里您必须更好地启动所有硬处理以异步任务将其移至后台,否则您将卡住应用程序,否则会突然出现意外情况崩溃.

这是您的异步​​任务示例,该任务在后台解析Json API响应,并按参数键入结果.

class ParseJsonInBackground<T> extends AsyncTask<String, VoID, APIResponseModel<T>> {    private ProcessResponse<T> func;    private Type inClass;    public ParseJsonInBackground(ProcessResponse<T> f, Type inClass){        this.func = f;        this.inClass = inClass;    }    @OverrIDe    protected voID onPreExecute() {        super.onPreExecute();    }    @OverrIDe    protected APIResponseModel<T> doInBackground(String... Json) {        Gson gson = new Gson();        try {            APIResponseModel<T> result = (APIResponseModel<T>) gson.fromJson(Json[0], inClass);            return result;        }catch(Exception e){            APIResponseModel<T> result = new APIResponseModel<T>();            result.data = null;            result.success = false;            result.error = new ArrayList<>();            result.error.add(new ErrorModel(0, "Parsing error", "Parsing error"));            return result;        }    }    @OverrIDe    protected voID onPostExecute(APIResponseModel<T> result) {        Utils.hIDeLoadingProgress(mContext);        if(result != null && func != null){            if(result.success){                func.onSuccess(result);            }else{                func.onError(result);            }        }    }}

并示例如何调用:

new ParseJsonInBackground<T>(responseFunc, inClass).execute(Json.toString());

注意! -不要在处理过程中使用任何视图,因为这会阻塞主线程,使数据库处理处于类似的异步任务中,不要经常写入数据库以进行事务记录.

总结

以上是内存溢出为你收集整理的Android在片段和服务之间发送消息全部内容,希望文章能够帮你解决Android在片段和服务之间发送消息所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1120687.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-29
下一篇 2022-05-29

发表评论

登录后才能评论

评论列表(0条)

保存