UI冻结在IntentService中运行多个线程



因此,在我的Android应用程序中,我有一项意图服务,可以贴上设备,并找到它们是否在线/离线。

当我启动IntentService时,我的UI冻结(调试指向何时执行ping命令)在服务中。

我获得网络呼叫的响应

后的父活动开始服务
loadFragment(printersFrag, Constants.CONTAINER_ACT_DASHBOARD, PrintersListingFragment.class.getSimpleName(), false, false, false);
serviceIntent = new Intent(this, PrinterPingIntentService.class);
serviceIntent.putExtra("PrinterList", printersResponse);
this.startService(serviceIntent);

我的意图服务的代码如下:

public class PrinterPingIntentService extends IntentService {
    /**
     * The IP Address to ping
     */
    private String msIPAddressToPing = null;
    /**
     * Countdown latch instance to decrement after the thread is done
     */
    private CountDownLatch mCountDownLatch;
    /**
     * Handler to handle ping threads
     */
    private PingHandler mPingThreadHandler = null;
    /**
     * Volatile count variable to manage the ping thread count
     */
    private volatile int mnPingThreadCount = 0;
    /**
     * The currently list of valid IP Addresses
     */
    private ConcurrentHashMap<String, Device> mPrinterMap = new ConcurrentHashMap<String, Device>();
    public PrinterPingIntentService() {
        super(PrinterPingIntentService.class.getName());
    }
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Bundle bundle = intent.getExtras();
        PrintersResponseBean printerResponse = bundle.getParcelable("PrinterList");
        for (int i = 0; i < printerResponse.getDevices().size(); i++) {
            mPrinterMap.put(printerResponse.getDevices().get(i).getDeviceIP(), printerResponse.getDevices().get(i));
        }
        validatePrinterIP();
    }
    @Override
    public void onCreate() {
        super.onCreate();
        /*
        * Fire up the Ping handler
        */
        mPingThreadHandler = new PingHandler();
    }
    /**
     * Validate the PrinterIPs by pinging them
     *
     * @author 
     */
    private void validatePrinterIP() {
        try {
            mnPingThreadCount = 0;
            mCountDownLatch = new CountDownLatch(mPrinterMap.size());
            for (String sIP : mPrinterMap.keySet()) {
                PingRunnable runnable = new PingRunnable(sIP, mCountDownLatch);
                Thread thread = new Thread(runnable);
                ++mnPingThreadCount;
                Log.d("BAT", "validatePrinterIP - Thread count - " + mnPingThreadCount);
                thread.start();
            }
        } catch (Exception e) {
            Log.d("BAT", "Exception validatePrinterIP - " + e.getMessage());
        }
    }
    /**
     * Runnable to make a ping to the given Ip Address
     *
     * @author 
     */
    public class PingRunnable implements Runnable {
        ////////////////////////////////// CLASS MEMBERS ///////////////////////////////////////////
        /**
         * The IP Address to ping
         */
        private String msIPAddressToPing = null;
        /**
         * Countdown latch instance to decrement after the thread is done
         */
        private CountDownLatch mCountDownLatch;
        ////////////////////////////////// CLASS METHODS ///////////////////////////////////////////
        public PingRunnable(String sIPAddress, CountDownLatch latch) {
            msIPAddressToPing = sIPAddress;
            mCountDownLatch = latch;
        }
        @Override
        public void run() {
            try {
                /*
                 * If the destination is not reachable, remove the IP address
                 * from the printer map and set the bundle value accordingly
                 */
                if (!pingURL(msIPAddressToPing)) {
                    Log.d("BAT", "Could not ping " + msIPAddressToPing + ". Removing from Map");
                    mPrinterMap.remove(msIPAddressToPing);
                } else {
                    Log.d("BAT", "Could ping " + msIPAddressToPing + ". Present in Map");
                }
            } catch (Exception e) {
                Log.d("BAT", "Exception in Ping Runnable - " + e.getMessage());
            } finally {
                mPingThreadHandler.sendEmptyMessage(0);
                mCountDownLatch.countDown();
            }
        }
    }
    /**
     * Static Handler class to handle messsages.
     * Reduce the count by one each time we receive a message to keep
     * track that all threads have returned
     *
     * @author 
     */
    public class PingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Log.d("BAT", "Returning thread..");
            if (msg.what == 0) {
                mnPingThreadCount--;
                Log.d("BAT", "Thread Return count - " + mnPingThreadCount);
            }
            /*
            Await Latch
             */
            try {
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                Log.d("BAT", "InterruptedException PingHandler - " + e.getMessage());
            }
            if (mnPingThreadCount == 0) {
                //////TEMP
                Log.d("BAT", "All threads accounted for. Final Printer List...");
                ArrayList<Device> onlinePrinters = new ArrayList<>();
                for (String sIP : mPrinterMap.keySet()) {
                    onlinePrinters.add(mPrinterMap.get(sIP));
                    Log.d("BAT", "Printers Active " + sIP);
                }
                //send data back to fragment via localBroadcastReceiver
                Intent localBroadcast = new Intent();
                localBroadcast.putParcelableArrayListExtra("onlinePrinters", onlinePrinters);
                localBroadcast.setAction("printer");
                sendBroadcast(localBroadcast);
            }
        }
    }
    /**
     * Ping a device. First we try the usual isReachable method. If that does not work,
     * we go with the Ping command execution
     *
     * @param sURL THe uRL / IP Address to ping
     * @author 
     */
    public boolean pingURL(String sURL) {
        try {
            Log.d("BAT", "Pinging IP sURL");
            //First try with isReachable
            if (Inet4Address.getByName(sURL).isReachable(1000)) {
                Log.d("BAT", "Host Reachable by InetAddress " + sURL);
                return true;
            }
            //else try and ping. If neither works, we return false
            else {
                Log.d("BAT", "Host Not Reachable by InetAddress. Pinging IP with RunTime... " + sURL);
                StringBuffer echo = new StringBuffer();
                Runtime runtime = Runtime.getRuntime();
                Process proc = runtime.exec("ping -c 1 " + sURL);
                // "/system/bin/ping -c 8 "  + sURL
                int nReturnVal = proc.waitFor();
                Log.d("BAT", "Done Pinging - " + sURL + ((nReturnVal == 0) ? " Successful" : " Unsuccessful"));
                return (nReturnVal == 0);
            }
        } catch (IOException e) {
            Log.d("BAT", "IOEXception in pingURL - " + e.getMessage().toString());
        } catch (InterruptedException e) {
            Log.d("BAT", "InterruptedException in pingURL - " + e.getMessage());
        } catch (Exception e) {
            Log.d("BAT", "EXception in pingURL - " + e.getMessage());
        }
        return false;
    }
}

从我的意图服务中,我使用以下方式将活动设备的数据发送到我的片段:

//send data back to fragment via localBroadcastReceiver
Intent localBroadcast = new Intent();
localBroadcast.putParcelableArrayListExtra("onlinePrinters", onlinePrinters);
localBroadcast.setAction("printer");
sendBroadcast(localBroadcast);

并在我的片段中提取此信息:

IntentFilter filter = new IntentFilter();
filter.addAction("printer");
updateUIReceiver = new BroadcastReceiver() {
   @Override
   public void onReceive(Context context, Intent intent) {
     //UI update here
     Bundle bundle = intent.getExtras();
     if (bundle.get("onlinePrinters") != null) {
        onlinePrinters = (ArrayList) bundle.get("onlinePrinters");
        setPrinterStatus();
     }
   }
};

由于我使用的是inistentservice,在工作线程上执行任务而不是在主线程中,ui冻结不太可能。

无法找出UI冻结的根本原因

  • onCreate()您服务的方法在主线程上调用。
  • PingHandler您正在创建的实例与主线程关联。
  • 因此,此处理程序的handleMessage也在主线程上执行。您似乎在那里进行了阻塞操作,这可能是您问题的原因。

最新更新