2011-07-15 127 views
1

我正在尝试构建一个简单的应用程序来下载和播放音乐文件。我做了一个代码,但当试图测试它,应用程序冻结并显示'启动超时已过期,放弃唤醒锁'如果任何人有一个想法,请给我一点建议?以下是我的代码。下载时模拟器冻结

顺便说一句,我试图下载的示例文件大小约为9.1MB。

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    try { 
     setDataSource("http://cfs.tistory.com/custom/blog/66/661632/skin/images/Believe.mp3"); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

private void setDataSource(String path) throws IOException {   

    URL url = new URL(path); 
    HttpURLConnection cn = (HttpURLConnection) url.openConnection(); 
    cn.setRequestMethod("GET"); 
    cn.setDoOutput(true); 
    cn.connect(); 

    String file_path = Environment.getExternalStorageDirectory()+"/download/"; 
    String fileName = "Temp.wav"; 
    File file = new File(file_path); 
    file.mkdir(); 

    InputStream is = cn.getInputStream(); 
    File output_file = new File(file, fileName); 
    FileOutputStream fos = new FileOutputStream(output_file); 

    byte[] buffer = new byte[4096]; 
    int read = 0; 

    while ((read = is.read(buffer)) > 0){ 
     fos.write(buffer, 0, read); 
    } 
    is.close(); 
    fos.close(); 

    mp = new MediaPlayer(); 
    mp.setDataSource(file_path+fileName); 
    mp.prepare(); 
    mp.start(); 

} 

}

**修改:**贾斯汀教我,如果我只是把它的onCreate(),然后它会导致一个问题。现在,我正在使用带有线程的按钮,但有另一个问题,说只有创建视图层次结构的原始线程可以触及其视图,看起来好像是在'fos.close'处发生的。如果有人知道该怎么做,你能帮我吗?

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    tv = (TextView) findViewById(R.id.tv1); 
    tv2 = (TextView) findViewById(R.id.tv2); 
    tv.setText(Environment.getExternalStorageDirectory()+"/download/"); 

    Button btn = (Button) findViewById(R.id.button1); 
    btn.setOnClickListener(new OnClickListener(){ 

     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      Thread thread; 
      Runnable r = new Runnable(){ 
       public void run(){ 
        try { 
         setDataSource("http://cfs.tistory.com/custom/blog/66/661632/skin/images/Believe.mp3"); 
        } catch (IOException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        }      
       } 
      }; 
      thread = new Thread(r); 
      thread.start(); 

     } 

    }); 
} 

**错误消息:**


07-15 04:31:45.321: ERROR/AndroidRuntime(313): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
+0

谢谢贾斯汀和安妮 – June

回答

1

的问题是,你的方法阻止较长时间的UI线程,因此Android是强制关闭应用程序。

尝试在onCreateMethod()的后台线程中启动长时间运行的进程,然后在完成时更新UI。

,以了解如何应用多线程最好的方法是查看使用它的谷歌示例应用程序之一。这是第一个链接的引用。

"We highly recommend reading the source code of Shelves to see how to 
persist tasks across configuration changes and how to cancel them 
properly when the activity is destroyed." 

更新:你应该将媒体播放器返回到UI线程,并有后台线程运行,然后更新时,它的完成为食媒体播放器的字符串。您可能需要重构以使用异步任务并将媒体播放器创建移动到onPostExecute()。您可能想要在此停止并尝试使用Async Task并查看Shelves应用程序如何执行多线程。

您可以在我上面提到的第一个URL(靠近页面底部)找到Shelves应用程序的链接。

+0

嗨,贾斯汀。感谢您的回复。在这种情况下,那么你会让我知道我可以放置这个'setDataSource'方法吗? – June

+0

感谢您对贾斯汀的大力帮助。我现在看到它不冻结我的应用程序,但仍然存在超时问题。如果你不介意,你会多帮我一点吗?我将在两分钟内尽快上传主要问题上的修改代码。 – June

+0

我知道了贾斯汀。谢谢你的解释。我现在要关闭这个主题 – June

0

打电话。像这样的setDataSource

在您的活动中,让一个处理程序在下载音乐文件时获取控件。

Handler h1 = new Handler(){ 
    public void handleMessage(Message msg){ 
     // put the check here to see 
    } 
}; 

new Thread(new Runnable(){ 

public void run(){ 
    // set your datasource here 

    // back to your handler 

} 
}){ 
}.start(); 
+0

感谢您的回复success_anil。实际上,我自己创建了自己的线程,它似乎解决了问题,但现在我遇到了另一个问题,即“只有创建视图层次结构的原始线程才能触及其视图。”我在主要问题上添加了这个内容,并想问问你,如果你不介意的话,你能否帮我解决这个问题? – June

+0

这就是为什么我使用处理程序进行回答可以更好地解决问题....在上面的代码中,内部运行方法执行此操作.. hi.sendMessage(h1.obtainMessage());并在处理程序的handleMessage内检查文件是否已下载...并使用文件 –

+0

再次感谢您的答复,anil。如果可能的话,你会帮我一个忙吗?我试图实现你的代码,但它给我一个又一个的语法错误,似乎有点难以修复。我很抱歉问你能否为我制作完整的代码? – June