Apache一些常用名命令:
# 安装服务
httpd -k install -n apache
# 启动服务
net start apache
httpd -k start -n apache
# 关闭服务
net stop apache
httpd -k stop -n apache
# 重启服务
httpd -k restart -n apache
# 卸载服务
## 卸载服务时先停止
httpd -k stop -n apache
## 再卸载服务
httpd -k uninstall -n apache
下载zip文件知识点:
(1)使用HttpURLConnection进行http下载
(2)使用AsyncTask创建异步任务
(3)申请权限
将zip文件写到sdcard知识点
(1)创建保存目录
(2)写文件
(3)下载完成返回标志
解压zip文件到指定目录知识点
(1)将zip包内文件解压到指定目录
(2)将zip文件删除
注意:Android高版本不能使用http协议
解决方法:清单文件里面添加(application中)
android:usesCleartextTraffic="true"
|
注意:还需要在清单里面申请使用网络的权限(application外)、读sd卡权限、写sd卡权限、管理sd卡权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
MainActivity.java
package a.b.c.testdwonloadzip;
import android.os.Bundle; import android.view.View; import android.widget.TextView;
import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets;
}); TextView tv = findViewById(R.id.tv_downResult); findViewById(R.id.btn_startDownload).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { DownloadZip downloadZip = new DownloadZip(tv); downloadZip.execute("http://192.168.31.197/down/test.zip"); } }); findViewById(R.id.btn_startzip).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { UnzipFile unzipFile = new UnzipFile(tv); unzipFile.execute(""); } }); } }
|
DownloadZip.java
package a.b.c.testdwonloadzip;
import android.os.AsyncTask; import android.os.Environment; import android.util.Log; import android.widget.TextView;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection;
public class DownloadZip extends AsyncTask<String,String,String> { private TextView tv; private String ret = ""; public DownloadZip(TextView ptv) { tv = ptv; }
@Override protected String doInBackground(String... strings) { HttpURLConnection httpURLConnection = null; InputStream inputStream = null; OutputStream outputStream; FileOutputStream outputStreamToFle;
try { URL url = new URL(strings[0]); httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.connect(); if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { Log.d("DownloadZip", "nor error code" + httpURLConnection.getResponseCode()); return "code error"; } inputStream = httpURLConnection.getInputStream(); outputStream = httpURLConnection.getOutputStream();
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/" + "zipSaveDir/"); if (dir.exists()) { dir.mkdir(); } String fullFile = dir + "/" + "2058.zip"; File file = new File(fullFile); if (file.exists()) { file.delete(); } file.createNewFile(); outputStreamToFle = new FileOutputStream(file.getAbsoluteFile());
byte[] buffer = new byte[1024]; int count; while (true) {
count = inputStream.read(buffer); if (count == -1) { break; } outputStreamToFle.write(buffer, 0, count); } outputStreamToFle.close(); ret = "success"; }catch (Exception ee) { ee.printStackTrace(); ret = "fail"; }finally { try { if(inputStream !=null) { inputStream.close(); } if(httpURLConnection!=null) { httpURLConnection.disconnect(); } }catch (Exception ee) { ee.printStackTrace(); } } return ret; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); if(ret.equals("success")) { tv.setText("下载success"); } else { tv.setText("下载fail"); } } }
|
UnzipFile.java
package a.b.c.testdwonloadzip; import android.os.AsyncTask; import android.os.Environment; import android.widget.TextView;
import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class UnzipFile extends AsyncTask { private String ret = ""; InputStream inputStream = null; ZipInputStream zipInputStream = null; OutputStream outputStream = null; TextView tv; public UnzipFile(TextView ptv) { tv = ptv; } @Override protected Object doInBackground(Object[] objects) { try { File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/" + "zipSaveDir/"); String fullFilePath = dir + "/" + "2058.zip"; File file = new File(fullFilePath); if(file.exists()) { String jieyaDir = dir.getAbsolutePath(); inputStream = new FileInputStream(file); zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream)); byte[] buffer = new byte[1024]; ZipEntry zipEntry; while((zipEntry = zipInputStream.getNextEntry())!= null ) { String fileName = zipEntry.getName(); if(zipEntry.isDirectory()) { File subDir = new File(jieyaDir + "/"+fileName); subDir.mkdirs(); continue; } int rCount;
FileOutputStream fout = new FileOutputStream(jieyaDir + "/"+fileName); while((rCount = zipInputStream.read(buffer))!=-1) { fout.write(buffer,0,rCount); } fout.close(); zipInputStream.closeEntry(); }
zipInputStream.close(); ret = "unzip success"; } else { ret = "file not exits"; } }catch (Exception ee) { ee.printStackTrace(); } return ret; }
@Override protected void onPostExecute(Object o) { super.onPostExecute(o); if(ret.equals("unzip success")) { tv.setText("解压成功"); } else { tv.setText("解压失败"); } } }
|
认识Handler
简介:Handler是一套Android消息传递机制,主要用于线程间通信,异步消息处理。
场景:主线程负责更新UI,子线程干活并反馈给主线程结果
使用例子:
1、sendMessage、post区别?
看一看Handler类源码post函数
2、主线程handler、子线程handler区别?
3、Message是个容器,卡车,装箱
4、先写代码,然后画个图?
和SDK的消息队列一样
底层原理:线程同步
线程同步回顾:
synchronized、wait()、notify()
模型:
生产者消费者
底层原理:线程同步-缓冲区:
具备条件:
使用synchronized
有入队操作
有出队操作
生产者:Handler
生产消息:sendMessage post
目标:Msg.target = this
消费者:Looper
如何消费:
1、死循环获取消息loop()
2、队列获取消息 next()
3、派发消息 对应Handle的处理函数handleMessage()
MainActivity
package a.b.c.testhandler;
import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.TextView;
import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat;
public class MainActivity extends AppCompatActivity {
private MyHandler myHandler; private TextView tv;
public void updateUI01() { tv.setText("01"); } public void updateUI02() { tv.setText("02"); } public void updateUI03() { tv.setText("03"); } public void updataUI04() { tv.setText("04"); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); myHandler = new MyHandler(this); SubThreadCreateHander subThread = new SubThreadCreateHander(); subThread.start();
tv =findViewById(R.id.tv_view); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(false) { MyThread myThread = new MyThread(myHandler); myThread.start(); myHandler.post(new Runnable() { @Override public void run() { for(int i=0;i<5;i++) { try { Thread.sleep(2000); updateUI01(); updateUI02(); tv.setText("i:"+i); } catch (InterruptedException e) { throw new RuntimeException(e); } } } });
}
Message message = Message.obtain(); message.what = 99; Bundle bundle = new Bundle(); bundle.putString("key1","这条内容是先放入Bundle,然后通过Message传递"); message.setData(bundle); subThread.subHandler.sendMessage(message); } }); } }
|
MyHandler
package a.b.c.testhandler; import android.os.Handler; import android.os.Message; import android.util.Log;
import androidx.annotation.NonNull; public class MyHandler extends Handler { private MainActivity mainActivity; public MyHandler(MainActivity pmainActivity) { mainActivity = pmainActivity; } @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); Log.i("MyHandler","in handleMessage"); switch (msg.what) { case 1: { mainActivity.updateUI01(); break; } case 2: { mainActivity.updateUI02(); break; } case 3: { mainActivity.updateUI03(); break; } case 4: { mainActivity.updataUI04(); break; }
} } }
|
MyThread
package a.b.c.testhandler; import android.os.Message; public class MyThread extends Thread { private MyHandler mh; public MyThread(MyHandler mh) { this.mh = mh; } @Override public void run() { super.run(); for(int i=0;i<5;i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } Message message = Message.obtain(); message.what =i; mh.sendMessage(message); } } }
|
SubThreadCreateHander
package a.b.c.testhandler; import android.os.Message; public class MyThread extends Thread { private MyHandler mh; public MyThread(MyHandler mh) { this.mh = mh; } @Override public void run() { super.run(); for(int i=0;i<5;i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } Message message = Message.obtain(); message.what =i; mh.sendMessage(message); } } }
|
Handler总结
在Android开发中,Handler是一种用于与线程间通信的机制,它允许你发送和处理消息和Runnable对象,从而在不同的线程之间执行代码。主要用途是在后台线程执行耗时操作后,将结果传递给主线程更新UI,或者实现定时任务等功能。
主要用途和特点:
线程间通信:
- 在Android中,UI更新必须在主线程(UI线程)中执行,而耗时操作(如网络请求、文件读写等)需要在后台线程执行,为了在这两者之间进行通信,可以使用Handler机制。
消息处理和处理机制:
- Handler可以用来发送消息(Message)或者投递任务(Runnable)到特定的线程消息队列中,这些消息或任务会按照一定的顺序执行。
主要组件:
- Looper:一个线程本地的消息循环机制,用来不断地从消息队列中取出消息或任务,并将其分发给对应的Handler处理。
- MessageQueue:用来存放所有待处理的消息或任务。
- HandlerThread:一种带有Looper的线程类,通常用于后台线程的创建和消息处理。
主要方法和用法:
- **sendMessage(Message)**:将Message对象发送到Handler关联的消息队列中。
- **post(Runnable)**:将Runnable对象发送到Handler关联的消息队列中,用于执行一些任务。
- **handleMessage(Message)**:处理从消息队列中取出的Message对象,通常在Handler的子类中重写这个方法来处理消息。
主线程操作:发送消息到主线程,在主线程中使用Handler,可以将消息或任务发送到主线程的消息队列中,以便在主线程上处理UI更新和其他操作。
示例:
假设在一个后台线程中执行了一个耗时操作(例如网络请求),操作完成后需要更新UI显示结果。
Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MESSAGE_NETWORK_RESPONSE: String response = (String) msg.obj; textView.setText(response); break; } } };
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
Message message = handler.obtainMessage(); message.what = MESSAGE_NETWORK_RESPONSE; message.obj = "Response from server"; handler.sendMessage(message); } }).start();
|
在这个示例中:
- 主线程中创建了一个Handler对象,并重写了
handleMessage
方法来处理接收到的消息。
- 在后台线程中执行了一个模拟的网络请求耗时操作(通过Thread.sleep来模拟),操作完成后通过Handler发送了一个包含网络请求结果的消息到主线程。
- 主线程接收到消息后,根据消息的类型(
MESSAGE_NETWORK_RESPONSE
),更新了TextView的显示内容。
这样,通过Handler可以实现在后台线程执行耗时操作后,将结果发送到主线程更新UI的功能。
2. 后台线程操作:发送消息到后台线程
尽管主要用途是在主线程和后台线程之间进行通信,但是也可以使用Handler在后台线程之间发送消息。这种情况比较少见,但在特定场景下可能会有用,例如在一个长时间运行的后台线程中执行任务,然后将任务结果或状态消息发送给另一个后台线程
示例:
假设有两个后台线程,一个线程负责执行某种计算任务,另一个线程监听并处理计算结果。
Handler backgroundHandler1 = new Handler(Looper.getMainLooper()); Handler backgroundHandler2 = new Handler(Looper.getMainLooper());
new Thread(new Runnable() { @Override public void run() { int result = performCalculation();
Message message = backgroundHandler2.obtainMessage(); message.what = MESSAGE_CALCULATION_RESULT; message.arg1 = result; backgroundHandler2.sendMessage(message); } }).start();
new Thread(new Runnable() { @Override public void run() { backgroundHandler2.post(new Runnable() { @Override public void run() { switch (msg.what) { case MESSAGE_CALCULATION_RESULT: int result = msg.arg1; break; } } }); } }).start();
|