Only one Looper may be created per thread问题

empty_1994 2015-07-29 09:22:11
我在ui线程创建一个handler和一个子线程,再在子线程建了一个handler,在子线程的handler里面去模拟一个耗时操作,但是运行时一直提示我 Only one Looper may be created per thread,我好像并没有在一个线程里面开两个handler啊,各位大侠可否帮我看一看。感激不敬

这个是MainActivity
public class MainActivity extends Activity {

private Button caculateButton;
private EditText input;
private TextView output;
private ProgressBar progressBar;
private CaculateThread cacThread;
private Handler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
caculateButton = (Button) findViewById(R.id.caculate);
progressBar = (ProgressBar) findViewById(R.id.process);
input = (EditText) findViewById(R.id.inputView);
output = (TextView) findViewById(R.id.outputView);
// 点击事件将得到数传给子线程去进行计算
caculateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int num = Integer.parseInt(input.getText().toString());
Message msg = new Message();
msg.what = 0x123;
Bundle data = new Bundle();
data.putInt("num", num);
progressBar.setMax(num);
progressBar.setMax(0);
progressBar.setProgress(0);
cacThread.getHandler().sendMessage(msg);
}
});
// 当前线程来接收计算线程计算的结果
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x321) {
List<Integer> nums = new ArrayList<Integer>();
nums = (List<Integer>) msg.getData()
.getSerializable("nums");
output.setText(nums.toString());
} else if (msg.what == 0x111) {
int total = msg.getData().getInt("total");
int current = msg.getData().getInt("current");
progressBar.setMax(total);
progressBar.setProgress(current);
}
}
};
cacThread = new CaculateThread(mHandler);
cacThread.run();
}

}

这个是线程
public class CaculateThread extends Thread {

private CaculateHandler handler;
private Handler parentHandler;

public CaculateThread(Handler handler) {
// 获取父线程
parentHandler = handler;

}

@Override
public void run() {
Looper.prepare();
this.handler = new CaculateHandler(parentHandler);
Looper.loop();
}

public CaculateHandler getHandler() {
return handler;
}

public void setHandler(CaculateHandler handler) {
this.handler = handler;
}
}

耗时操作的handler
public class CaculateHandler extends Handler {

private Handler parentHandler;
private int total = 0;
private int current = 0;

public CaculateHandler(Handler handler) {
parentHandler = handler;
}

@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {
int num = msg.getData().getInt("num");
total = num;
List<Integer> nums = new ArrayList<Integer>();
for (int j = 3;; j = j + 2) {
int k = 2;
for (; k < j; k++) {
if (j % k == 0) {
break;
}
}
// 为质数
if (j == k) {
nums.add(j);
current = nums.size();
{
Message procMsg = new Message();
procMsg.what = 0x111;
Bundle data = new Bundle();
data.putInt("total", total);
data.putInt("current", current);
procMsg.setData(data);
// 将消息传给ui线程
parentHandler.sendMessage(procMsg);
}
// 如果达到需要的数量,将质数发送出去
if (nums.size() >= num) {
Message outMsg = new Message();
outMsg.what = 0x321;
Bundle data = new Bundle();
data.putSerializable("nums", (Serializable) nums);
outMsg.setData(data);
// 将消息传给ui线程
parentHandler.sendMessage(outMsg);
}
}
}
}
}
}
...全文
2104 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
流浪重耳 2016-08-29
  • 打赏
  • 举报
回复
引用 楼主 empty_1994 的回复:
我在ui线程创建一个handler和一个子线程,再在子线程建了一个handler,在子线程的handler里面去模拟一个耗时操作,但是运行时一直提示我 Only one Looper may be created per thread,我好像并没有在一个线程里面开两个handler啊,各位大侠可否帮我看一看。感激不敬 这个是MainActivity
public class MainActivity extends Activity {

	private Button caculateButton;
	private EditText input;
	private TextView output;
	private ProgressBar progressBar;
	private CaculateThread cacThread;
	private Handler mHandler;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		caculateButton = (Button) findViewById(R.id.caculate);
		progressBar = (ProgressBar) findViewById(R.id.process);
		input = (EditText) findViewById(R.id.inputView);
		output = (TextView) findViewById(R.id.outputView);
        // 点击事件将得到数传给子线程去进行计算
		caculateButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				int num = Integer.parseInt(input.getText().toString());
				Message msg = new Message();
				msg.what = 0x123;
				Bundle data = new Bundle();
				data.putInt("num", num);
				progressBar.setMax(num);
				progressBar.setMax(0);
				progressBar.setProgress(0);
				cacThread.getHandler().sendMessage(msg);
			}
		});
		// 当前线程来接收计算线程计算的结果
		mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == 0x321) {
					List<Integer> nums = new ArrayList<Integer>();
					nums = (List<Integer>) msg.getData()
							.getSerializable("nums");
					output.setText(nums.toString());
				} else if (msg.what == 0x111) {
					int total = msg.getData().getInt("total");
					int current = msg.getData().getInt("current");
					progressBar.setMax(total);
					progressBar.setProgress(current);
				}
			}
		};
		cacThread = new CaculateThread(mHandler);
		cacThread.run();
	}
	
}
这个是线程
public class CaculateThread extends Thread {

	private CaculateHandler handler;
	private Handler parentHandler;

	public CaculateThread(Handler handler) {
		// 获取父线程
		parentHandler = handler;
		
	}

	@Override
	public void run() {
		Looper.prepare();
		this.handler = new CaculateHandler(parentHandler);
		Looper.loop();
	}

	public CaculateHandler getHandler() {
		return handler;
	}

	public void setHandler(CaculateHandler handler) {
		this.handler = handler;
	}
}
耗时操作的handler
public class CaculateHandler extends Handler {

	private Handler parentHandler;
	private int total = 0;
	private int current = 0;

	public CaculateHandler(Handler handler) {
		parentHandler = handler;
	}

	@Override
	public void handleMessage(Message msg) {
		if (msg.what == 0x123) {
			int num = msg.getData().getInt("num");
			total = num;
			List<Integer> nums = new ArrayList<Integer>();
			for (int j = 3;; j = j + 2) {
				int k = 2;
				for (; k < j; k++) {
					if (j % k == 0) {
						break;
					}
				}
				// 为质数
				if (j == k) {
					nums.add(j);
					current = nums.size();
					{
						Message procMsg = new Message();
						procMsg.what = 0x111;
						Bundle data = new Bundle();
						data.putInt("total", total);
						data.putInt("current", current);
						procMsg.setData(data);
						// 将消息传给ui线程
						parentHandler.sendMessage(procMsg);
					}
					// 如果达到需要的数量,将质数发送出去
					if (nums.size() >= num) {
						Message outMsg = new Message();
						outMsg.what = 0x321;
						Bundle data = new Bundle();
						data.putSerializable("nums", (Serializable) nums);
						outMsg.setData(data);
						// 将消息传给ui线程
						parentHandler.sendMessage(outMsg);
					}
				}
			}
		}
	}
}
楼主你和我犯了一样的错误 有可能是对Thread长时间没用了手误将启动线程start换成run start是开启一个线程会穿件Looper实例 run是直接运行run方法当然会出错 基础不牢又不细心中毒很深啊
流浪重耳 2016-08-29
  • 打赏
  • 举报
回复
奇怪了上面代码两个Msg值出错但是修正了还是有这个问题,改成这样就没问题了: package com.study.touchevent.demo; import android.app.Activity; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { /** * 程序说明: * 主线程发送消息弹出吐司 普通looper线程发送消息弹出吐司 */ public static final int Msg_MianThread_come=1; public static final int Msg_LooperThread_Come=2; private Handler superHandler; private Handler looperhandler; private Context mContext; private Button btn_mian; private Button bt_normal; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; new LooperThread().start(); btn_mian = (Button) findViewById(R.id.btn1); bt_normal = (Button) findViewById(R.id.btn2); btn_mian.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (superHandler != null) { superHandler.sendEmptyMessage(Msg_MianThread_come); } } }); bt_normal.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (looperhandler != null) { looperhandler.sendEmptyMessage(Msg_LooperThread_Come); } } }); superHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); int what = msg.what; switch (what){ case Msg_MianThread_come: Toast.makeText(mContext, "主线程消息", Toast.LENGTH_LONG).show(); break; default: break; } } }; } /** * 普通线程 */ class LooperThread extends Thread { @Override public void run() { // TODO Auto-generated method stub Looper.prepare(); looperhandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); int what = msg.what; switch (what){ case Msg_LooperThread_Come: Toast.makeText(mContext, "子线程消息", Toast.LENGTH_LONG).show(); break; default: break; } } }; Looper.loop(); } } } 自己都没发现那个地方有区别
流浪重耳 2016-08-29
  • 打赏
  • 举报
回复
我的也有这个问题 package com.study.touchevent.demo; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { public static final int Msg_MyThread_Come=1; public static final int Msg_MianThread_come=1; public Handler handler; public Handler looperhandler; public Button btn1; public Button btn2; public Context mContex; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContex=this; new LooperThread().run(); handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); int what=msg.what; switch (what){ case Msg_MianThread_come: Toast.makeText(mContex,"主线程消息",Toast.LENGTH_LONG).show(); break; default: break; } } }; btn1 = (Button) findViewById(R.id.btn1); btn2 = (Button) findViewById(R.id.btn2); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(handler!=null){ handler.sendEmptyMessage(Msg_MianThread_come); } } }); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(looperhandler!=null){ looperhandler.sendEmptyMessage(Msg_MyThread_Come); } } }); } public class LooperThread extends Thread{ @Override public void run() { /* if(Looper.myLooper()!=null){ Looper.prepare(); }*/ Looper.prepare(); looperhandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); int what=msg.what; switch (what){ case Msg_MyThread_Come: Toast.makeText(mContex,"子线程消息",Toast.LENGTH_LONG).show(); break; default: break; } } }; Looper.loop(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
boy_nihao 2015-12-10
  • 打赏
  • 举报
回复
楼主现在找到原因了吗 解决了没
boy_nihao 2015-12-10
  • 打赏
  • 举报
回复
刚学looper 我写了个类似的demo并未出现你的问题。
gao_chun 2015-07-29
  • 打赏
  • 举报
回复
你的这个类:public class CaculateThread extends Thread 里头的这个方法 Looper.prepare(); prepare() 这个函数为我们提供初始化Looper对象,这个函数告诉我们只要你调了这个方法,那么系统就会在ThreadLocal内添加一个Looper对象,并且一个线程只能有一个Looper,若超出一个,则会抛出异常.
gao_chun 2015-07-29
  • 打赏
  • 举报
回复
感觉是这里的问题:
 @Override
    public void run() {
        Looper.prepare();
        this.handler = new CaculateHandler(parentHandler);
        Looper.loop();
    }
这个异常是试图在已经有Looper的线程中再次创建Looper时会出现的. Looper源码:
public class Looper {  
   
    private static final ThreadLocal sThreadLocal = new ThreadLocal();  
    
    final MessageQueue mQueue;  
    
    Thread mThread;  
      
  
     
    private Looper() {  
        mQueue = new MessageQueue();  
        mRun = true;  
        mThread = Thread.currentThread();  
    }  
  
    //调用该方法会在调用线程的TLS中创建Looper对象  
    public static final void prepare() {  
        if (sThreadLocal.get() != null) {  
		//你出现的异常
            throw new RuntimeException("Only one Looper may be created per thread");  
        }  
        sThreadLocal.set(new Looper());  
    }  

    //.....
}  

80,350

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧