创建GUI更新线程

时间:2013-12-21 00:59:12

标签: android listview android-arrayadapter

我创建了一个自定义ArrayAdapter,它显示了包含图像,文本和数据字段的列表视图,可以通过修改一组全局变量来更新。我可以初始化接口并验证通过更改全局变量我可以更改列表视图,但只能从OnCreate()中更改。因此,我尝试使用notifyDataSetChanged()创建一个每200ms更新listview的线程,但我似乎无法启动该线程。试图调用.start();会产生一个错误,指出“类型MainActivity的方法start()未定义”。任何帮助将不胜感激。

MainActivity

public class MainActivity extends Activity
{

    // Sensor Constants
    public static String temperature;
    public static String humidity;
    public static String lpg;
    public static String alcohol;
    public static int temperature_int;
    public static int humidity_int;
    public static int lpg_int;
    public static int alcohol_int;


    // Layout
    ListView listView;
    ItemAdapter adapter;


    // USB
    UsbManager USB_Manager;
    UsbDevice Sense;
    PendingIntent permission;
    IntentFilter filter;
    //BroadcastReceiver receiver;
    //USBBuffer_s_received_data = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //Initialize Interface
        Model.LoadModel();
        listView = (ListView) findViewById(R.id.listView);
        String[] ids = new String[Model.Items.size()];
        for (int i= 0; i < ids.length; i++)
        {ids[i] = Integer.toString(i+1);}
        ItemAdapter adapter = new ItemAdapter(this,R.layout.row, ids);
        listView.setAdapter(adapter);

        //USB
        if ((UsbManager) getSystemService(Context.USB_SERVICE) != null)
        {
            USB_Manager = (UsbManager) getSystemService(Context.USB_SERVICE);
            if (USB_Manager.getDeviceList().values().iterator().next() != null)
            {
                Sense = USB_Manager.getDeviceList().values().iterator().next();
                if ((UsbDevice) getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE) != null)
                {
                    Sense = (UsbDevice) getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
                }
            }
        }


        // Update Layout
        temperature_int = 30; humidity_int = 6; lpg_int = 5000; alcohol_int = 500;
        temperature = String.valueOf(temperature_int);
        humidity = String.valueOf(humidity_int);
        lpg = String.valueOf(lpg_int);
        alcohol = String.valueOf(alcohol_int);


        Model.LoadModel();
        listView.setAdapter(adapter);
        adapter.notifyDataSetChanged();
        GUI_Update();
    }   

    @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;
    }

    public void GUI_Update()
    {
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                while (true)
                {
                    try
                    {
                        Thread.sleep(200);
                        Model.LoadModel();
                        listView.setAdapter(adapter);
                        adapter.notifyDataSetChanged();
                    }
                    catch (InterruptedException e)
                    {
                    }
                }

            }
        });
        //.start();
    }

修改 移动.start()的位置修复了问题,但现在应用程序在启动后立即退出,我不确定原因。这是我得到的错误日志..

12-20 17:22:11.010: D/libEGL(15395): loaded /vendor/lib/egl/libEGL_POWERVR_SGX540_120.so
12-20 17:22:11.010: D/libEGL(15395): loaded /vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so
12-20 17:22:11.018: D/libEGL(15395): loaded /vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so
12-20 17:22:11.096: D/OpenGLRenderer(15395): Enabling debug mode 0
12-20 17:22:11.369: W/dalvikvm(15395): threadid=11: thread exiting with uncaught exception (group=0x4198ac68)
12-20 17:22:11.377: E/AndroidRuntime(15395): FATAL EXCEPTION: Thread-711
12-20 17:22:11.377: E/AndroidRuntime(15395): Process: com.byrdonatwigge.sense, PID: 15395
12-20 17:22:11.377: E/AndroidRuntime(15395): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6094)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:857)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.ViewGroup.invalidateChild(ViewGroup.java:4320)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.View.invalidate(View.java:10942)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.View.invalidate(View.java:10897)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.widget.ImageView.invalidateDrawable(ImageView.java:201)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.graphics.drawable.Drawable.invalidateSelf(Drawable.java:344)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.graphics.drawable.Drawable.setVisible(Drawable.java:575)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.widget.ImageView.onDetachedFromWindow(ImageView.java:1243)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.View.dispatchDetachedFromWindow(View.java:12627)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2585)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:4027)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.widget.AbsListView.resetList(AbsListView.java:1924)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.widget.ListView.resetList(ListView.java:521)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at android.widget.ListView.setAdapter(ListView.java:462)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at com.byrdonatwigge.sense.MainActivity$2.run(MainActivity.java:445)
12-20 17:22:11.377: E/AndroidRuntime(15395):    at java.lang.Thread.run(Thread.java:841)
12-20 17:22:12.127: D/AndroidRuntime(15395): Shutting down VM
12-20 17:22:12.127: W/dalvikvm(15395): threadid=1: thread exiting with uncaught exception (group=0x4198ac68)
12-20 17:22:12.127: I/Process(15395): Sending signal. PID: 15395 SIG: 9

编辑#2 * 更新主题 *

private void GUI_Update()
    {
        new Thread()
        {
            public void run()
            {
                while (true)
                {
                    try
                    {
                        runOnUiThread(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                Model.LoadModel();
                                listView.setAdapter(adapter);
                                adapter.notifyDataSetChanged();
                            }
                        });
                        Thread.sleep(500);
                    }
                    catch (InterruptedException e)
                    {
                    }
                }
            }
        }.start();
    }

日志

12-20 18:49:49.741: D/dalvikvm(17054): Late-enabling CheckJNI
12-20 18:49:50.085: D/libEGL(17054): loaded /vendor/lib/egl/libEGL_POWERVR_SGX540_120.so
12-20 18:49:50.092: D/libEGL(17054): loaded /vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so
12-20 18:49:50.100: D/libEGL(17054): loaded /vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so
12-20 18:49:50.186: D/OpenGLRenderer(17054): Enabling debug mode 0
12-20 18:50:09.405: D/AndroidRuntime(17117): Shutting down VM
12-20 18:50:09.405: W/dalvikvm(17117): threadid=1: thread exiting with uncaught exception (group=0x4198ac68)
12-20 18:50:09.405: E/AndroidRuntime(17117): FATAL EXCEPTION: main
12-20 18:50:09.405: E/AndroidRuntime(17117): Process: com.byrdonatwigge.sense, PID: 17117
12-20 18:50:09.405: E/AndroidRuntime(17117): java.lang.NullPointerException
12-20 18:50:09.405: E/AndroidRuntime(17117):    at com.byrdonatwigge.sense.MainActivity$2$1.run(MainActivity.java:449)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at android.os.Handler.handleCallback(Handler.java:733)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at android.os.Handler.dispatchMessage(Handler.java:95)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at android.os.Looper.loop(Looper.java:136)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at android.app.ActivityThread.main(ActivityThread.java:5081)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at java.lang.reflect.Method.invokeNative(Native Method)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at java.lang.reflect.Method.invoke(Method.java:515)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:781)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-20 18:50:09.405: E/AndroidRuntime(17117):    at dalvik.system.NativeStart.main(Native Method)

4 个答案:

答案 0 :(得分:0)

您应该在.start()构造函数的最后)之前移动Thread

public void GUI_Update()
{
    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            while (true)
            {
                try
                {
                    Thread.sleep(200);
                    Model.LoadModel();
                    listView.setAdapter(adapter);
                    adapter.notifyDataSetChanged();
                }
                catch (InterruptedException e)
                {
                }
            }

        }
    }).start();  // here

这应该让它运行。但是,我不确定你为什么要这样做。每200毫秒更换一次是非常快的,我不确定你打算用这个来完成什么。此外,拥有无限loop并不是一个好主意。

答案 1 :(得分:0)

您应该将Runnable对象发布到原始线程以实现此目的。

但这是一种更复杂的解决方案。 (仅在由于其他原因而无法保持相同方法时才使用)

请改用TimeTask。它将以更清洁,更简单的方式为您的目的服务。
希望这会有所帮助。

答案 2 :(得分:0)

如果您只是需要安排将来发生的事情,则不需要线程。

一个简单的类,不幸的是不适合你的用例是Android的CountDownTimer。它允许您安排重复事件,直到达到限制。您可以使用某种无限限制。

另一方面,您可以使用基于Handler的略微修改的版本。 Handler可以安排在UI线程中发生的事件。

public abstract class Ticker {
    private final long mPeriod;
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    public Ticker(long period) {
        mPeriod = period;
    }

    public final void start() {
        stop();
        mHandler.post(mTick);
    }

    public final void stop() {
        mHandler.removeCallbacks(mTick);
    }

    private final Runnable mTick = new Runnable() {
        @Override
        public void run() {
            mHandler.postDelayed(mTick, mPeriod);
            onTick();
        }
    };

    /** Called every period ms */
    public abstract void onTick();
}


public class Foo extends Activity {

    private Ticker mTicker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTicker = new Ticker(200) {
            @Override
            public void onTick() {
                // update things
            }
        };
        mTicker.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTicker.stop();
    }
}

答案 3 :(得分:0)

如果你想在主线程上运行代码,这是我发现的最简单的解决方案。任何时候你想要更新UI,它都必须在主线程上,否则它将失败或什么都不做。

new Handler(Looper.getMainLooper()).post(new Runnable() {

    @Override
    public void run() {
        // code to run on main thread
    }
})