5

我正在尝试开发一个使用线程来实现幻灯片的应用程序。我正在从 SQLite 检索图像路径并将它们显示在 ImageView 上。我感到震惊的问题是,我很困惑,所以我无法理解,我从哪个线程调用 images() 方法,我实际上是在哪里实现幻灯片。

我得到的Logcat如下 -

    09-03 13:47:00.248: E/AndroidRuntime(10642): FATAL EXCEPTION: Thread-151
09-03 13:47:00.248: E/AndroidRuntime(10642): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-03 13:47:00.248: E/AndroidRuntime(10642):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)

09-03 13:47:00.248: E/AndroidRuntime(10642):    at com.example.fromstart.MainActivity.images(MainActivity.java:90)
09-03 13:47:00.248: E/AndroidRuntime(10642):    at com.example.fromstart.MainActivity$2.run(MainActivity.java:59)
09-03 13:47:00.248: E/AndroidRuntime(10642):    at java.lang.Thread.run(Thread.java:841)

MainActivity.java:

public class MainActivity extends Activity
{
    ImageView jpgView;
    TextView tv;

    //adapter mDbAdapter;   
    adapter info = new adapter(this);
    String path; 
    Handler smHandler = new Handler() 
    {
        public void handleMessage(Message msg) 
        {
            TextView myTextView = 
            (TextView)findViewById(R.id.textView1);
            myTextView.setText("Button Pressed");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        jpgView = (ImageView)findViewById(R.id.imageView1);
        tv = (TextView) findViewById(R.id.textView1);
    }
    @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);


        final Runnable runnable = new Runnable() 
        {
                 public void run() 
                 {
                            images();
                 }
        };
        int delay = 1000; // delay for 1 sec.
        int period = 15000; // repeat every 4 sec.
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() 
        {
            public void run() 
            {
                smHandler.post(runnable);
            }
        }, delay, period);
        Thread mythread = new Thread(runnable);
        mythread.start();
        return true;
}
        public void handleMessage(Message msg) 
        {             
            String string = "sample";
            TextView myTextView = (TextView)findViewById(R.id.textView1);
            myTextView.setText(string);
        }
        public void images()
        {
            try
            {
                 for(int i=0;i<=20;i++)
                {
                     path = info.getpath();
                Bitmap bitmap = BitmapFactory.decodeFile(path);
                jpgView.setImageBitmap(bitmap);

                }
            }
            catch(NullPointerException er)
            {
                String ht=er.toString();
                Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
            }
         }
    }

我是 android 的新手,刚刚开始研究 Threads。如果您在我的代码中发现任何错误,请指出这些错误并建议我处理此问题的正确方法。

提前致谢。

更新:

 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final Handler mHandler = new Handler();

    // Create runnable for posting
    runOnUiThread(new Runnable() 
    {
        public void run() 
        {
            images();
        }
    });
    int delay = 1000; // delay for 1 sec.
    int period = 15000; // repeat every 4 sec.
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() 
    {
        public void run() 
        {
            images();
        }
    }, delay, period);




}

public void images()
{
    try
    {

    Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG).show();
             path = info.getpath(); 
             Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_LONG).show();
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        Toast.makeText(getApplicationContext(), "3", Toast.LENGTH_LONG).show();
        jpgView.setImageBitmap(bitmap);
        Toast.makeText(getApplicationContext(), "4", Toast.LENGTH_LONG).show();

    }
    catch(NullPointerException er) 
   {
            String ht=er.toString();
            Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
    }
     }

}
4

2 回答 2

8

您不能从线程更新/访问 ui。

你有这个

     public void run() 
     {
           images();
     }

在图像中你有

    jpgView.setImageBitmap(bitmap);

您需要runOnUiThread用于更新 ui。

    runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                      // do something
                    }
                });

TimerTask 也在不同的线程上运行。所以你已经使用了一个处理程序来更新用户界面。

您可以使用处理程序。

编辑:

Handler m_handler;
Runnable m_handlerTask ;  
m_handler = new Handler();   
m_handlerTask = new Runnable()
{
  @Override 
  public void run() { 

    // do something. call images() 
    m_handler.postDelayed(m_handlerTask, 1000);    

  }
  };
 m_handlerTask.run();

如果您仍希望使用计时器任务,请使用runOnUiThread

timer.scheduleAtFixedRate(new TimerTask() 
    {
        public void run() 
        {
              runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                      images();
                    }
                }); 

        }
    }, delay, period);
于 2013-09-03T18:04:55.633 回答
4

要从任何其他线程更新 UI,您必须使用

runOnUiThread(<Runnable>);

这将更新您的 UI。

例子:

runOnUiThread(
     new Runnable()
                 { 
                  // do something on UI thread Update UI
                 });
于 2013-09-03T18:31:14.753 回答