我在开发一个简单的应用程序,为了在android环境下练习线程,我得到了一个常见的错误,但我不知道为什么,可能是因为线程的行为,或者我不知道为什么。
主活动类
public class MainActivity extends AppCompatActivity {
MiHiloLooper looper;
ImageView iv1, iv2, iv3;
URL url1, url2, url3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
iv1 = new ImageView(getApplicationContext());
iv1.setImageResource(R.drawable.hilo1);
iv2 = new ImageView(getApplicationContext());
iv2.setImageResource(R.drawable.hilo2);
iv3 = new ImageView(getApplicationContext());
iv3.setImageResource(R.drawable.hilo3);
try {
url1 = new URL("https://www.dhresource.com/0x0/f2/albu/g8/M00/E6/A3/rBVaV15BFzGAdY2NAARdO9TdaIk347.jpg/20s-3-1500-yards-length-polyester-thread.jpg");
url2 = new URL("https://images-na.ssl-images-amazon.com/images/I/714bmMviZEL._AC_SY450_.jpg");
url3 = new URL("https://www.brildor.com/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/h/p/hps025200.jpg");
}catch (MalformedURLException e){
Toast miToast = Toast.makeText(getApplicationContext(), "Se ha produido un error al cargar las imagenes", Toast.LENGTH_LONG);
miToast.setGravity(Gravity.CENTER, 0, 0);
miToast.show();
}
looper = new MiHiloLooper();
looper.post(new Thread( new ImageLoader(url1, iv1) ));
looper.post(new Thread( new ImageLoader(url2, iv2) ));
looper.post(new Thread( new ImageLoader(url3, iv3) ));
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Lanzammos los hilos con el OnClick del Toolbar.
}
});
}
@Override
protected void onDestroy() {
looper.terminate();
super.onDestroy();
}
@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);
}
}
imageloader.class类
public class ImageLoader implements Runnable {
ImageView iv;
URL url;
Button button;
public ImageLoader(URL url, ImageView iv){
this.iv = iv;
this.url=url;
}
@Override
public void run() {
try {
InputStream is = url.openStream();
final Drawable drawable =
Drawable.createFromStream(is, "src");
button.post(new Runnable() {
@Override
public void run() {
iv.setImageDrawable(drawable);
}
});
} catch (IOException e) {
Log.e("URL","Error downloading image "+
url.toString());
}
}
}
MIHILOOPER.类
public class MiHiloLooper extends Thread{
Handler handler; //message handler
public MiHiloLooper(){
this.start();
}
@Override
public void run(){
try{
Looper.prepare();
handler = new Handler();
Looper.loop();
}catch(Throwable t){
Log.e("Looper","Error: ", t);
}
}
public void terminate(){
handler.getLooper().quit();
}
public void post(Runnable runnable){
handler.post(runnable);
}
}
这是我的应用程序的结构,我得到的错误是:
2020-11-21 17:47:11.166 4078-4078/com.example.probandohilos E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.probandohilos, PID: 4078
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.probandohilos/com.example.probandohilos.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.post(java.lang.Runnable)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.post(java.lang.Runnable)' on a null object reference
at com.example.probandohilos.MiHiloLooper.post(MiHiloLooper.java:27)
at com.example.probandohilos.MainActivity.onCreate(MainActivity.java:53)
at android.app.Activity.performCreate(Activity.java:7009)
at android.app.Activity.performCreate(Activity.java:7000)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
我不明白我怎么能得到一个 NullPointerException
,如果我已初始化 Looper
以及它需要的所有参数。
如果你告诉我哪里错了,提前谢谢!
2条答案
按热度按时间pkmbmrz71#
原因是
mHandler
为空,因为MiHiloLooper
线程与发布同步创建Runnable/messages
使用itspost
方法。所以,当你试图
looper.post()
在线程创建结束之前(即run()
结束),然后你将面对这个npe。为了便于说明,要使代码在没有npe的情况下运行,可以使用
Thread.sleep()
为了确保MiHiloLooper
线程是在向其循环程序发布任何runnable之前创建的。我在这里等了几秒钟,以确保looper
线程已创建并mHandler
不为空。同样,这是为了说明的目的,当然不是一种生产方式。
因此,要解决您的问题,您需要使用调用
post()
方法。你可以用一个监听器接口来解决这个问题,只要你的线程被创建,监听器接口就会被触发。
下面是自定义线程的新代码,我将侦听器作为构造函数参数传递;并调用了它的回调
onReady()
每当处理程序初始化时,我确信mHandler
将不再为空。然后在你的
MainActivity
添加一个侦听器作为构造函数参数。旁注:您可以添加
synchronized
给你的post()
方法以避免提交给可运行程序的任何争用条件MiHiloLooper
线程。b1zrtrql2#
根本原因
在线程上调用start()时,它不会立即执行,系统需要为该线程分配资源,然后在run()方法中运行代码,在该方法中初始化处理程序。这就解释了为什么在访问处理程序时会出现npe(nullpointerexception)。
解决方案
如果你想创建一个有活套的线程,android为你提供handlerthreadapi。因此,请将代码更改为:
mihilooper.java文件
主活动.java
顺便说一下,imageloader类中有一行
这个
button
变量未在任何地方初始化,因此它将使应用程序崩溃。在这种情况下,可以替换为iv
变量。最后,您不应该创建新线程并将其传递给处理程序的post()方法。
不要
做